views:

137

answers:

1

In a navigation based app, I initialize an array in my app delegate without using self. When accessed in the RootViewController's cellForRowAtIndexPath:, all array objects are there and I can see it is an NSCFArray. Once the app loads, I click a table cell and in didSelectRowAtIndexPath:, that same array has a type of NSArray, no objects and I get a EXC_ BAD_ACCESS error. If I precede the array with self in the app delegate, all is fine. Why is that?

Below is the app delegate .h file:

@interface MyAppDelegate : NSObject <UIApplicationDelegate> {

  UIWindow *window;
  UINavigationController *navigationController;
  NSMutableDictionary *aDict;
  NSArray *aArray;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@property (nonatomic, retain) NSArray *aArray;
@property (nonatomic, retain) NSArray *aDict
@end

The array and dictionary are synthesized in the .m file. I initialize the array in the app delegate .m file like this:

aArray = [self.aDict allKeys];

It is accessed like this in both root controller methods:

theDelegate = [[UIApplication sharedApplication] delegate]; 
[theDelegate.aArray objectAtIndex:2];

Only when I reach didSelectRowAtIndexPath: does it fail. Doing this in the app delegate makes everything work:

self.aArray = [self.aDict allKeys];

I didn't do anything to myArray between cellForRowAtIndexPath: and didSelectRowAtIndexPath:. Why does it fail in the first scenario?

+5  A: 

That is because self.aArray makes use of the synthesized property. You defined the property as (nonatomic, retain), this means that whatever it is set to, that value will be retained. What was happening when you didn't use this was that the allKeys was being auto-released, and by the time you actually used it, it was gone. Using the property retained that value, making it live past its scope.

Hope that made sense, sorry if I misunderstood you.

Further reading:

I'm sure there are more reader friendly articles out there, but now you know what to look up: Objective-C memory management, and Objective-C properties. It's pretty important so I recommend you do this.

Jorge Israel Peña
Thanks. Why was the autorelease occurring "only" at the time between the two root controller methods and not before cellForRowAtIndexPath: for example? cellForRowAtIndexPath: had already accessed aArray two times (2 rows). Is it random? One more thing: What is it (myArray) called when you don't use 'self'? Using 'self' accesses the property but not using it means...
4thSpace
Not using self is just setting it directly. You really have to read up on how properties work. Properties are just auto-generated methods that set the variable but in the way you define (retain, copy, etc.). You could have the same behavior if you just wrote your own setter/getter methods, but properties do this automatically and also let you use the self.something syntax. properties basically just save you some grunt work, time, and redundancy.
Jorge Israel Peña
And yes, autoreleased objects can be considered to release randomly. Actually, they are usually released when the pool they are in gets released, I suggest you read up on autoreleased objects as well. The pool is NSAutoreleasePool, I'll include a link in my post. So it's not completely random per se, but you shouldn't make any assumptions and just retain/copy in such situations.
Jorge Israel Peña
So 4thSpace, did I answer your question? If so, I'd appreciate it if you accepted the answer.
Jorge Israel Peña
Is there a way to force this behavior? I've setup a simple app that uses the above scenario without the dictionary. So there is only an array on the app delegate. I can't get it to fail. I'm not using self in the app delegate when accessing the instance variable.
4thSpace
What are you using instead of the dictionary keys to set the value of the array?
Jorge Israel Peña