Releasing reference to UIApplication's delegate results in EXC BAD ACCESS, why? - iphone

I am running my application through xcode's static analyzer and it pointed out that I had a potential leak in a file:
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
So after the code I do [delegate release]. This results in an EXC BAD ACCESS when the view controller I am doing this in pushes a new view controller onto the navigation stack. If I comment this out, it's fine.
I have run through the debugger and it doesn't actually crash when the delegate reference is released, but just when the next controller is pushed.
It isnt the code which runs between the declaration and the release as I tried commenting it out to see what happens.

Calling the delegate Method does not retain the object. So you shouldn't be in charge of releasing it. Are you sure that the static analyzer is referencing this particular line of code? UIApplication itself does not retain but assign the delegate.

In your code you just get a reference to the application delegate object and do not retain it anywhere - so you should not release it.
So either static analyzer gives false positive here or there's some other error in the code around. But, again, considering just this line you should not release delegate.

Related

NSDictionary retain crash

I have a NSDictionary, storing value by parsing. I am allocating and storing value in -viewDidLoad. And accessing the values in -viewWillAppear. It works perfectly fine.
Then, I have UIPageControl with UIScrollView. While scrolling the UIScrollView, again I am accessing the same dictionary, it crashes saying
[CFString respondToSelector:]: send to deallocated....
- (void) viewDidLoad {
[super viewDidLoad];
scoresDict = [[NSDictionary alloc] initWithDictionary:[scoreObj scores]];
}
- (void)loadScrollViewWithPage:(int)page {
if (page < 0)
return;
if (page >= kNumberOfPages)
return;
NSLog(#“scoresDict %#”,scoresDict);
}
I tried using retain in the same function, it didn’t work out. And copy, it also didn’t work. Any help would be appreciated. Thanks!
You don't say so, but it looks like all of these methods are being called from an instance of your custom UIViewController or UIScrollViewController subclass.
The most likely problem is that this instance itself isn't being retained.
When you first load the view from the nib, both -viewDidLoad and -viewWillAppear are called. It's possible, however, that garbage collection is happening in between those calls and your call to -loadScrollViewWithPage, and that no object has any connection to the view controller instance itself.
If that's the case, using copy or retain on the scoresDict won't solve the problem. You need to make sure that you are copying or retaining the view controller instance itself. Figure out what object needs to be retaining your view controller and make sure it is being retained.
A quick way to test whether this is the problem or not: create a "myViewController" property in your application delegate. In viewDidLoad, add a line:
[[[UIApplication sharedApplication] delegate] setMyViewController:self];
If this fixes your problem, it means the problem was the view controller getting released. That doesn't mean this is your best solution, though--it's just a diagnostic. You need to figure out what should be retaining your view controller and make sure it does so.

When should I release [[UIApplication sharedApplication] delegate] object?

I'm using the following code many times in my app (especially to manage a NavigationController):
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
When should I release it ?
Thx for helping,
Stephane
Don't. Never release your application delegate - it is managed automatically by the OS.
If you look in your app's main.m file, you'll see some code that initializes an instance of UIApplication that represents your app - it is its responsibility to manage the application delegate's lifecycle, not your responsibility.
EDIT as #Goz points out, you should release it if at some point you retain it. However, since the application object (and therefore, by extension its delegate) is guaranteed to remain in scope for the life of the app (unless you go messing with it), it's far better to simply not do any memory management on the delegate, as this avoids the possibility of accidental over-release or other related issues.
Short answer: never ever release your application delegate.
Explanation:
It often helps me how to address mem-mgmt issues, when I check how the things are declared. Take a look how delegate property is declared for UIApplication:
#property(nonatomic,assign) id<UIApplicationDelegate> delegate;
As you can see, it is assigned property meaning all mem-mgmt done here is just assigning pointers for an instance variable. It means calling release on your application delegate will result in -dealloc method being executed for your MyAppDelegate. Go and try this in debugger and you'll see that your application will receive EXC_BAD_ACCESS - i.e. it will crash.
EDIT: However, as Goz suggests, you can call retain and then release. But in the first place, it doesn't make sense to do this retain/release thing on app delegate.

UIViewController not being dealloc-ed under the new ARC memory management

I am pushing my UIViewController subclass onto the navigation stack; however, since it is being retained by the navigationController, I 'release' my pointer to it after pushing it onto the stack so that when it is eventually popped the viewController will be dealloc-ed.
However, it's not working, the dealloc method for the viewController is never called. The code looks something like this:
MyViewController *newViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"foo"];
[self.navigationController pushViewController:newViewController animated:YES];
newViewController = nil;
Even in the following code, my newViewController is not being dealloc-ed:
MyViewController *newViewController =
[self.storyboard instantiateViewControllerWithIdentifier:#"foo"];
newViewController = nil;
From what I understand, under the new Automatic Reference Counting (ARC) system, objects are dealloc-ed once nothing points to it. I put a NSLog method in the dealloc method of the viewController that is being created, but it is never called.
What am I missing here?!
Thanks for reading my first post on stack overflow :)
**EDIT:**
I apologise. I tried the second piece of code wrapped in an autorelease pool and it was deallocated. I then tried it without the autorelease pool and it deallocated properly too. I don't know what happened last night.
(2nd edit: and now its stopped working again. fffffffuuuuuuuuuuuu)
In your first example, it would be very odd if the new view controller were deallocated, since you just pushed it onto the navigation controller, and thus the navigation controller has a strong reference to it. The object will only be deallocated when ALL strong references are gone.
In your second example, it's possible that the returned object still has pending releases from autorelease calls that were performed internal to the implementation of instantiateInitialViewController. Thus, until the current autorelease pool is drained, you wouldn't see it disappear. Further, it's possible that the UIStoryboard class caches the returned object as an optimization.
In short, even with ARC you still cannot assume that objects you receive from framework methods will be deallocated immediately when you're done with them, because you cannot guarantee that autorelease was not used in that method's implementation.

Objective-C: Point of releasing a View

I made a static mainmenu with a TableView. Sometimes it crashes because my Subview has allready deallocated a subview.
Is also ok to release a View in the dealloc method of the local object instead of that:
[NavController pushViewController:self.AnotherView animated:YES];
[self.AnotherView release]; //This line into (void)viewDidLoad
AnotherView is defined in the headerfile as property and also synchronozed in the .m-File
When i use the dealloc way it works great on the device, but I need to know if this is correct.
You only call release for objects you init or alloc yourself. If it is a property of your class then release in the dealloc of your class.
So in your case, unless you init anotherView a few lines above your sample code (same method), calling release on it where you are is going to cause a leak/SIG_ABORT because you have done so prematurely.
Feel free to post more code, particularly how anotherView is assigned and you may get a more specific answer.

Why does Core Data initialization fail when I attempt to do it at these points?

I see how to solve the problem but it bothers me that I don't understand why this doesn't work. I have a UIViewController subclass that uses Core Data, so it needs the NSManagedObjectContext. The controller is loaded from a nib file where it's placed under a navigation controller which is inside a tab controller.
I tried doing this in initWithCoder and viewDidLoad and for some reason it doesn't work:
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = [[appDelegate managedObjectContext] retain];
For some reason managedObjectContext returns nil and I get this when I try to create a managed object later:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an entity named 'LogRecord' in this model.'
Which is what you get when your context is nil or the model can't be loaded (or really lacks the entity).
If I do the exact same thing at the top of my saveLogEntry method (which creates managed objects and saves the context) then it works just fine.
If I do what the Recipes sample application does:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
loggingViewController.managedObjectContext = self.managedObjectContext;
// Standard stuff
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
}
(loggingViewController is an IBOutlet in the app delegate).
Does anyone know what specifically might be going on here? It seems like it fails if done "too early" but especially with viewDidLoad I'd expect it to work since I think that occurs after addSubview is called.
Do exactly what the recipes app does.
If you try it in initWithCoder, you don't know if the app delegate has finished initialization (which it hasn't)
If you try it viewDidLoad, you have a similar problem.
That is why you should NOT be accessing the app delegate like so:
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = [[appDelegate managedObjectContext] retain];
This is bad form. It introduces coupling into your design. Use dependency injection, just like the example. It makes your app more flexible.
Because from the app delegate you know exactly what initialization has been performed and can pass in the context at the appropriate time.
Update:
The issue is that your View Controller instance is likely being instantiated in the Mainwindow.xib. Mainwindow.xib (and any other nibs it references) is "defrosted" before the app delegate receives UIApplicationDidFinishLaunchingNotification notification.
The order in which objects are defrosted from nibs is not guaranteed. When initWithCoder: is called on your View Controller you have no idea what other objects have been defrosted from the nib. You also can't be sure whether the app delegate has received the UIApplicationDidFinishLaunchingNotification notification.
It is similar for viewDidLoad. In viewDidLoad, you can be sure that all other objects in the nib have been properly defrosted and initialized, but since the configuration of the app delegate happens outside of the nib file, you can't be sure whether it is safe to call the app delegate.
It is better just to have the app delegate pass in the context when it is "good and ready", preferably in the applicationDidFinishLaunching: method.
Hope that is a little clearer, you should take a look at the iphone programming guide:
http://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/index.html
To glean a better explanation of the iPhone application life cycle.
Hope that helps.
One More Update:
In depth discussion of the iphone launch sequence:
http://www.bit-101.com/blog/?p=2159