views:

228

answers:

1

My question is related to my discovery of a reason for UINavigationController to crash. So I will tell you about the discovery first. Please bare with me.

The issue: I have a UINavigationController as as subview of UIWindow, a rootViewController class and a custom MyViewController class. The following steps will get a Exc_Bad_Access, 100% reproducible.:

[myNaviationController pushViewController:myViewController_1stInstance animated:YES];
[myNaviationController pushViewController:myViewController_2ndInstance animated:YES];

Hit the left back tapBarItem twice (pop out two of the myViewController instances) to show the rootViewController.

After a painful 1/2 day of try and error, I finally figure out the answer but also raise a question.

The Solutio: I declared many objects in the .m file as a lazy way of declaring private variables to avoid cluttering the .h file. For instance,

#impoart "MyViewController.h"
NSMutableString*variable1;

@implement ...

-(id)init
{
   ...
   varialbe1=[[NSMutableString alloc] init];
   ...
}

-(void)dealloc
{
   [variable1 release];
}

For some reasons, the iphone OS may loose track of these "lazy private" variables memory allocation when myViewController_1stInstance's view is unloaded (but still in the navigation controller's stacks) after loading the view of myViewController_2ndInstance. The first time to tap the back tapBarItem is ok since myViewController_2ndInstance'view is still loaded. But the 2nd tap on the back tapBarItem gave me hell because it tried to dealloc the 1st instance. It called [variable release] resulted in Exc_Bad_Access because it pointed randomly (loose pointer).

To fix this problem is simple, declare variable1 as a @private in the .h file.

Here is my Question: I have been using the "lazy private" variables for quite some time without any issues until they are involved in UINavigationController. Is this a bug in iPhone OS? Or there is a fundamental misunderstanding on my part about Objective C? Please help.

+1  A: 

It might be related to both instances of your view controller using the same statically-allocated variable.

In other words, both myViewController_1stInstance and myViewController_2ndInstance are using the same variable1 location in memory and overwriting one another.

Variables declared inside of the curly braces after your @interface definition have a memory location allocated by the runtime for each instance of the class (every time you call [<ClassName> alloc]. Variables declared in the global scope (that is, outside of any functions or class declarations) are just that: global. That means that the variable can only hold one value per running copy of your application.

There are no truly private variables in Objective-C, but you can hide them from other instances at compile time as described here.

Frank Schmitt
This was also what I was guessing in the beginning. But it was not the case.
Wayne Lo
Even if you are sure that the static variables are not causing the problem, it is a bad idea to use static variables for per-instance data. That's what member variables are for.
Kristopher Johnson
They are not static. To declare static variable, enter as follows:static NSString variable1;
Wayne Lo
Any variables declared outside of functions/methods or class definitions are implicitly static.
Frank Schmitt
Thanks Frank. That's interesting and a good explanation for what I experienced. I am not sure why Objective adopt this implicit style. Can you point me to any online reference regarding this? How to you declare none static?
Wayne Lo
@Frank Schmitt: "Any variables declared outside of functions/methods or class definitions are implicitly static" is it? Then what are globals?
Manjunath
@Manjunath You're right that the proper term is "global", but by "static" I'm referring to them being statically allocated by the runtime before `main` is run, not the C language's overloading of the term to mean "a single instance local to this source file".
Frank Schmitt