How should I be sending a message with a field of the same object as its value? - iphone

In Objective-C, the compiler is complaining about the following line of code:
if ([self getLength(self.identifier)] < givenWidth * kMarginAllowance)
This is getting the error "Expected ']'", and the caret below the text is on the parenthesis exactly after "getLength".
My suspicion is that my [self getLength(self.identifier)] is wrong in how it combines things.
What I want to say is "Fetch this object's identifier, and call this object's getLength() method."
I've tried a couple of permutations, and I don't think I'm using correct syntax.
What is the correct syntax for this type of thing?
--
My code is:
-(float)getLength:(NSString *)text
{
UIFont *font = [UIFont fontWithName:#"Scurlock" size:20];
CGSize size = [text sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]];
return size.width;
}
-(void)getFormattedString:(float)givenHeight width:(float)givenWidth
{
NSMutableArray *workbench = [NSMutableArray array];
if (getLength(self.identifier) < givenWidth * kMarginAllowance)
{
[workbench addObject:self.identifier];
}
else
{
// [Under development]
}
}
The included .h file has:
-(float) getLength:(NSString *)text;
There is a yellow warning in Xcode that indicates that the call to getLength() is an invalid implicit declaration. The character it specifically points to is the beginning of the getLength() call. If I try to run it, I get an "Apple Mach-O Linker Error", because _getLength is referenced and presumably doesn't turn anything up.
What is the root problem I'm causing here? Inlining the method might do what I want, but I'd rather fix it, and understand what the correct approach is.

Try
[self getLenght:self.identifier]
So it would be like this:
if ([self getLenght:self.identifier] < givenWidth * kMarginAllowance)
getLenght: is an Objective-C method but you're trying to call it as a C function.
Hope this helps!

if ( getLength(self.identifier) < (givenWidth * kMarginAllowance))

If getLength is an instance method
// calls getLength method on self.identifier
if ([self.identifier getLength] < givenWidth * kMarginAllowance)
if it is a C style function
if (getLength(self.identifier) < givenWidth * kMarginAllowance)

Related

How to name and handle memory management on a function that returns a CFType

I have a project running on ARC (DTCoreText) and I want to implement a category method on UIFont that returns a matching CTFontRef. This is what I have so far:
#implementation UIFont (DTCoreText)
+ (UIFont *)fontWithCTFont:(CTFontRef)ctFont
{
NSString *fontName = (__bridge_transfer NSString *)CTFontCopyName(ctFont, kCTFontPostScriptNameKey);
CGFloat fontSize = CTFontGetSize(ctFont);
return [UIFont fontWithName:fontName size:fontSize];
}
- (CTFontRef)CTFont
{
CTFontRef newFont = CTFontCreateWithName((__bridge CFStringRef)self.fontName, self.pointSize, NULL);
return newFont;
}
#end
Technically this returns a +1 reference since there is no autoreleasing CF objects.
In my code I am calling it like this:
- (void)replaceFont:(UIFont *)font inRange:(NSRange)range
{
[self beginEditing];
[self removeAttribute:(id)kCTFontAttributeName range:range];
CTFontRef ctFont = [font CTFont];
[self addAttribute:(id)kCTFontAttributeName value:CFBridgingRelease(ctFont) range:range];
[self endEditing];
}
This goes without Analyze warning because of the CFBridgingRelease, but I am worried about the need for that not being clear to somebody from the name of the category method.
A different suggestion has been to use a C-function for the creation instead:
static CTFontRef CTFontCreateFromUIFont(UIFont *font)
That would be more obvious because of the Create in the name which tells the developer that he is getting a +1 reference.
So what is the "correct" way in your opinion? Any other suggestions?
Another option would be to name the method something like createCTFont. I don't know whether the analyzer will consider that to imply CF's Create rule on a method; if it doesn't, you can add an annotation to explicitly declare that the method returns an ownership:
- (CTFontRef) createCTFont CF_RETURNS_RETAINED;
Naming the method this way should make the reader suspicious if no release follows the creation message, and the annotation will definitely make the analyzer suspicious in the same circumstance.

Why am I am getting the warning "Multiple methods named 'center' found"

I only get this warning if I import my helper class (#import "JLHelper.h").
An example of the where the warning occurs...
[[subViews objectAtIndex:i] center].y+translation.y)];
I understand that it is telling me that the compiler sees more than one method named center, but center is declared in the framework in CLRegion.h.
Why would the compiler see more than one method in this case? Is it a problem to be concerned about, and if so how do I track down and resolve it.
Thanks,
John
Problem solved, thanks to Eric! Here is a more extensive look at my code after it was fixed
NSArray *subViews = [self subviews];
UIImageView *bottomResizer;
int count = [subViews count];
for (int i =count-1; i>=0; i--) {
if([[subViews objectAtIndex:i] tag] == 301) {
bottomResizer = (UIImageView*)[subViews objectAtIndex:i];
[bottomResizer setCenter:CGPointMake([bottomResizer center].x, [bottomResizer center].y+translation.y)];
}
}
Looks like you need to cast the object so it knows what center you mean...
[((OBJECT_TYPE*)[subViews objectAtIndex:i]) center].y+translation.y)];
Where OBJECT_TYPE is a CLRegion Object

Method returns 0 instead of the number I assigned to the variable

I'm trying to get the basics of iOS programming down. I have an app that shows a random number when I click a button.. At least, that's what I wanted to make. However, it doesn't seem to be working out.
I have the following basic method which should set the text of myLabel to the return value of generateRandomNumber. However, it always returns 0. I think the syntax I'm using here is correct since it works for the commented parts:
-(IBAction)myBtnPressed:(UIButton *)sender
{
//[myLabel setText:#"test"];
//[myLabel setText:[NSString stringWithFormat:#"%g / 15", 3.14]];
[myLabel setText:[NSString stringWithFormat:#"%g / 15", [myModel generateRandomNumber]]];
}
The last line sets the label to display 0/15. However, in my model, I have the following code ('static' for now):
-(double)generateRandomNumber
{
randomNumber = 1.34;
return randomNumber;
}
It doesn't return the 1.34 and I don't understand why it doesn't. Can someone clear this up?
Update
This is the code for my viewcontroller.m file:
#import "myViewController.h"
#implementation myViewController
-(MyModel *)myModel
{
if (! myModel) {
myModel = [[MyModel alloc] init];
}
return myModel;
}
-(IBAction)myBtnPressed:(UIButton *)sender
{
[myLabel setText:[NSString stringWithFormat:#"%g / 15", [myModel generateRandomNumber]]];
}
#end
Also, in the end, I want to make generateRandomNumber return a random number between 0 and 15. How would I do this? Would a simple line like:
int x = arc4random() % 16;
work for this? Or do I have to seed it in some way so it doesn't always return the same values when I run the application?
Thanks in advance.
It doesn't return the 1.34 and I don't understand why it doesn't. Can someone clear this up?
Almost certainly, you haven't allocated and initialised the myModel object. You can send messages to nil without crashing but the return value will be 0.
arc4random() doesn't need a seed.
Edit
Your init code looks OK but you are not calling int, in your myBtnPressed: method, you need
[myLabel setText:[NSString stringWithFormat:#"%g / 15", [[self myModel] generateRandomNumber]]];
Are you instantiating an object of your model type? I'm asking because you say that you have declared the function in myModel.h (Could be a typo).
And yes - to get a random number between 0 and X:
int rand = arc4random() % X;
And you don't need to seed the generator.
To return a double between 0 and 15:
// define this somewhere
#define ARC4RANDOM_MAX 0x100000000
// and then use this
double val = floorf(((double)arc4random() / ARC4RANDOM_MAX) * 15.0f);
random-thoughts-rand-vs-arc4random.html for more.
Did you ever alloc/create the myModel object?
I'm guessing that you didn't, and you're just trying to use the class as a 'methods' class that doesn't store anything (I know there's a name for it, but I'm self taught so my terminology is pretty horrible!)
You can do this in objective-c, but you've got to use different syntax. Instead of using minus signs for the method declaration, use "+":
+(double)generateRandomNumber;
and now your method should be usable!

How to change the property of UILabels which store in a NSMutableArray

i am going to just add one UILabel into array as example
NSMutablearray *labels = [[NSMutableArray alloc] init];
UILabel *newLabel = [[UILabel alloc] initWithFrame:CGRectMake(100,100,20,20)];
newLabel.center = CGPointMake(100, 100);
[labels addObject:newLabel];
then later i want to change newLabel.center by doing something like this
[labels objectAtIndex:1].center.x +=10;
this gives me an error "request for member "center" in something not a structure or union"
then i try
[labels objectAtIndex:1]->center.x +=10;
then this gives me another error said struct objc_object has no member named 'center'
how can i change the property of UILabel that is store in NSMutableArray?
You are getting this error because the return type of objectAtIndex: is simply id (which can be any object); NSArray is a generic container, when you retrieve an object from it, there's no way to know what type it is. You know, because you put the objects in it, but the compiler doesn't know.
You wrote:
[labels objectAtIndex:1].center.x +=10;
That's technically correct, but the compiler can't type check it. It's equivalent to writing this:
id object = [labels objectAtIndex:1];
object.center.x +=10;
The second line is where the error occurs: the compiler knows object is an Objective-C object, but it doesn't know what class, so it doesn't know what properties have been defined, etc. So instead it tries to parse it as a structure field member access, which it's not, and it fails.
If you instead write:
UILabel *label = [labels objectAtIndex:1];
label.center.x +=10;
Now the compiler knows that label is an instance of UILabel, it knows about the property definitions, and it can generate the correct code.
Now you have a second problem, because you are changing a value within a structure. The second line above is shorthand for:
label.center.x = label.center.x + 10;
This is again shorthand for a Objective-C method call:
[label center].x = [label center].x + 10;
Because the center point is a CGPoint struct, you have to get/set the entire point value at once, you can't just update the x or y member. So again, you need to do it like this:
UILabel *label = [labels objectAtIndex:1];
CGPoint c = label.center;
c.x += 10;
label.center = c;
That will do what you want.
If you're tempted to say Objective-C is a stupid language because you need all the temporary variables... well, maybe, but be fair and understand you hit on two special cases in one example.

EXC_BAD_ACCESS Error for no conceivable reason

OK, This is a method from my program that keeps giving the EXC_BAD_ACCESS error and crashing. I indicated the line below. questionsShown is a readwrite property and points to an NSMutableArray that I initialize with a capacity of 99 at an earlier point in the program. When I debug everything appears normal in terms of the property being allocated. I assumed there must be some issue with memory management but I am having serious trouble finding the problem. Thanks in advance for any help.
#synthesize questionList;
#synthesize questionLabel;
#synthesize questionsShown;
-(IBAction)next{
int numElements = [questionList count];
int r;
if (myCount == numElements){
[questionLabel setText:#"You have seen all the questions, click next again to continue anyways."];
[questionsShown release];
questionsShown = [[NSMutableArray alloc] initWithCapacity:99];
myCount = 0;
}
else {
do {
r = rand() % numElements;
} while ([questionsShown indexOfObjectIdenticalTo:r] != NSNotFound);
NSString *myString = [questionList objectAtIndex:(NSUInteger)r];
[questionLabel setText:myString];
myCount++;
[questionsShown addObject:r]; //results in crash with message EXC_BAD_ACCESS
myCount++;
}
}
The EXC_BAD_ACCESS is coming from dereferencing r, which is just an integer. Your compiler should be giving you a warning (make pointer from integer without a cast) on that line.
If questionsShown is supposed to be some kind of index set for you (which it appears to be), you might want to either use that class, or you will have to box your integer in an NSNumber object. So:
[questionsShown addObject:[NSNumber numberWithInt:r]];
and when you read it:
[questionsShown indexOfObjectIdenticalTo:[NSNumber numberWithInt:r]]
I recommend, however, that you take a look at the NSIndexSet documentation.
With a mutable index set, you could do:
[questionsShownIndexSet containsIndex:r]
and
[questionsShownIndexSet addIndex:r]