views:

56

answers:

3

Hi there,

Im fairly new to the whole world of iPhone dev so forgive me if this is very easy. I have an object Card that holds 6 Question objects on it. when I say [card getQuestion:@"Art"] I am currently returning a Question object like so

- (Question*) getQuestion: (NSString*) questionType {
    Question *q = [questions objectForKey:questionType];
    return [q autorelease];
}

Question has a property of text (type NSString) which allows me to see what the text for the question is. So I want to use this text to update a UILabel in the viewController

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"%@", [[self.card getQuestion:@"Art"] qText]);
    self.myQuestion.text = [[self.card getQuestion:@"Art"] qText];
}

This crashes the iPhone, whereas if I change the function in object Card to this

- (NSString*) getQuestion: (NSString*) questionType {
    return [[questions objectForKey:questionType] qText];
}

and my call in the viewController to

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"%@", [self.card getQuestion:@"Art"]);
    self.myQuestion.text = [self.card getQuestion:@"Art"];
}

This works fine.. can anyone explain what I am doing wrong, in both cases the call to NSLog returns me the relevant text. In both cases the display loads but in the first instance it crashes shortly after, whereas the other way it stays stable.

Any help appreciated.

+5  A: 
- (Question*) getQuestion: (NSString*) questionType {
    Question *q = [questions objectForKey:questionType];
    return [q autorelease];
}

According to the memory management rules, you should not be autoreleasing that object, and this is almost certainly what is causing your crash. You're relinquishing ownership of an object you don't own, which is causing it to get deallocate prematurely. This means that when another object which is supposed to own the Question tries to access it, the Question is gone and you crash with an EXC_BAD_ACCESS error.

Additionally, the method should probably be called questionForType: or questionOfType:. Using the get prefix implies that the object will be returned via an out-parameter, which it's not.

Dave DeLong
That cracked it, thanks a lot, I took that autorelease stuff from another example I found somewhere, but I think that was not an iPhone app. Oh and thanks for the function hint, trying to get use to the naming conventions
Catharsis
A: 

I can see two errors,

1: You are releasing something you don't own (Question 'q') - If you do either alloc, copy or retain, you should release it. If not, you shouldn't.

2: The setter-line should be written like this:

Question *q = (Question *)[questions objectForKey:questionType];

That way you avoid getting warnings or errors.

Emil
1 is correct, 2 is unnecessary. `objectForKey:` returns an object of type `id`, which can safely be assigned into any object variable without casting.
Dave DeLong
I have sometimes encountered issues when not casting an object (for example a delegate).
Emil
A: 

Since you are new at all of this - you should definitely make sure you run your app looking for zombies and also run it with the instruments application to make sure you are not leaking anywhere.

You should read a very short explanation of memory mangement in Objective - C every few days - one day it will all sink in and become second nature.

http://macdevelopertips.com/objective-c/objective-c-memory-management.html

Tom Andersen
Yeah I have read and understood the basics of Obj C memory management, just a case of putting it into practise, it is the only way I am going to learn by doing it wrong. Thanks for the link, I bookmarked it and will read it a few times :)
Catharsis