dealloc is being called and I am not sure why - objective-c

I have a view with some buttons, text fields, and methods. When I load the view, switch to another view, and then switch back, my app crashes. I added in an NSLog in each method to see what the last method call before the crash was, and it was -(void)dealloc{
I am wondering why this method was called? Is it called every time you reload a view? I've double checked my code and I definitely do not call it anywhere.
EDIT : Found my problem, I was releasing an array that I was using to store views. Thanks to #Darren I traced my problem.

Dealloc is called when a class is no longer needed and removed from memory.
When you have no more pointers holding onto anything in the view, then it's dealocated.
How are you switching to/from the view?
if you set a (strong) pointer to the view then it won't be dealocated automatically.

-dealloc is called whenever an object's reference count drops to 0. To find your problem, figure out what object's -dealloc was called. What's the second method on the call stack? The third? Was -dealloc sent to a valid object pointer in the first place?
There are several ways to approach this sort of thing. A good first step is to turn on NSZombies (Google for it). That'll let you know if you're sending a message (like, say, dealloc) to an invalid object. Usually, that causes a crash, but with NSZombies you'll get a nice error message instead.

Related

An Objective-C message was sent to a deallocated object (zombie) at address: 0x75d52a0

I am relatively new to iOS development so appreciate your help in finding out the root cause for the error that I encountered.
I tried to debug the error using Instruments (i.e. Allocations-Zombie Profiler) but I could not make sense of the call stacks that were presented.
This is how the user interfaces are linked:
TabBarController -> NavigationController -> TopPlacesTableViewController -> RecentPhotosTableViewController -> PhotoViewController
The error occurs when I click on the Back button in the last view (i.e. that of the PhotoViewController). This action is supposed to show the previous RecentPhotosTableViewController but instead an unknown deallocated object was accessed, sometime in between the events of viewWillAppear and ViewDidAppear.
Additionally, I have a GenericTableViewController which is the parent of TopPlacesTableViewController and RecentPhotosTableViewController. The children set a NSMutableArray property in the parent which is the data that gets loaded in the children's views.
I am currently using iOS6 and XCode4.5.
[Update: In the Console, this line was shown - "[UIView _forgetDependentConstraint:]: message sent to deallocated instance xxx"].
I feel you are not using ARC, and you are not retaining of passing your previous object. In the meantime the previous object is released and then you accessing it.
Either you can refactor your code to use ARC or put retain or autorelease.
Go to Product > edit scheme >Diagnostics tap then check on enable Zombie objects
make a break point and go step by step to know which object is deallocated, it perhaps the pointer to your object has been removed then the OS has deallocated your object.

Memory management for reusing UIAlertView

Lets say I have multiple View controller classes using the same UIAlertView *alertView. *alertView's delegate is set to a centralized delegate.
I do this because would like to use the .tag to do different things based on it.
The question is every time I invoke an alert view or dismiss it, what do i have to do to prevent a memory leak?
Should I not release every time? Or is this a very bad idea?
Thanks.
A UIAlertView may be "shown" from anywhere in your app. I have an app that the main UIViewController has a timer that every so often brings up a UIAlertView. When that timer goes off, even if my main view being shown is from a completely different UIViewController (and thus view) the Alert will come to front.
If you really want to "actively" bring up the UIAlertView from any of your UIViewControllers (lets say based upon a user action), then I would do one of two things.
1) setup my Application Delegate Object with the UIAlertView implemented there, with accessor methods for invoking (showing) the Alert view, and thus freeing it from there also, or
2) Generate a singleton like object with the AlertView implemented there!!!
In either case then you can simply dealloc your UIAlertView once within the dealloc routine you write for either of those placements, and alloc it only once when the object is initialized.
Just treat it like you would any other object. If you want to keep it around, assign it to a retained property like: self.myAlert. You still need to release it like you normally would when creating it. The retained property will take care of keeping it around for you.
Always keep your retains(alloc's, copy's, etc...) and releases balanced.

Protecting my code from zombies from completion blocks

I'm familiar with the delegate pattern and nilling my delegates, especially when doing asynchronous calls which are still in progress when my view controllers disappear. I nil the delegate, and the callback successfully returns on a nil object.
I'm now experimenting with using completion blocks to make my code a little easier to read.
I call a network service from my view controller, and pass a block which updates my UITableView. Under normal circumstances it works fine. However, if I leave the view before it completes, the completion handler block is executed - but the UITableView is now a zombie.
Whats the usual pattern for handling this?
UPDATE WITH CODE SAMPLE
This is an iPad app, I have two view controllers on screen at once, like a split view. One is the detail, and the other is a grid of images. I click an image and it tell the detail to load the info. However, if i click the images too fast before they have chance to do the network call - I have the problems. On changing images the code below is called which counts the favourites of a image....
So here is my dilemma, if I use the code below - it works fine but it leaks in instruments if you switch images before the network responds.
If I remove the __block and pass in self, then it crashes with zombies.
I can't win... I'm sure i'm missing something fundamental about using blocks.
__block UITableView *theTable = [self.table retain];
__block IndexedDictionary *tableData = [self.descriptionKeyValues retain];
FavouritesController *favourites = [Container controllerWithClass:FavouritesController.class];
[favourites countFavouritesForPhoto:self.photo
completion:^(int favesCount) {
[tableData insertObject:[NSString stringWithFormat:#"%i", favesCount]
forKey:#"Favourites:" atIndex:1];
[theTable reloadData];
[tableData release];
[theTable release];
}];
Any tips? Thanks
SECOND UPDATE
I changed the way I loaded the favourites. Instead of the favourites being a singleton, I create an instance on each photo change. By replacing this and killing the old one - the block has nowhere to callback (i guess it doesn't even exist) and my code now just looks like the below, and it appear to be working:
[self.favourites countFavouritesForPhoto:self.photo
completion:^(int favesCount) {
[self.descriptionKeyValues insertObject:[NSString stringWithFormat:#"%i", favesCount]
forKey:#"Favourites:" atIndex:1];
[self.table reloadData];
}];
It doesn't leak, and doesn't appear to be crashing either.
I recommend you test that the tableview is not nil at the start of the block. It sounds like the tableview is properly discarded when its parent view goes off-screen, so after that point, no tableview operations are valid.
Retaining the UITableView within the block is a bad idea, because datasource/tableview updates can result in implicit method calls and notifications that will not be relevant if the tableview is not on-screen.
Block will retain any object that it references, except for those annotated with __block. If you want not to execute completion blocks at all, just make some property like isCancelled and check whether it is YES before calling completion block.
So you have a background operation which has to call back another object after it finishes and the object can be destroyed in the meantime. The crashes you describe happen when you have non retained references. The problem as you see is that the referred object goes away and the pointer is invalid. Usually, what you do is unregister the delegate inside the dealloc method so that the background task continues, and whenever it is ready to communicate the results back it says "Shoot, my callback object is nil", and at least it doesn't crash.
Still, handling manually weak references is tedious and error prone. You can forget to nil a delegate inside a dealloc method and it may go without notice for months before you encounter a situation where the code crashes.
If you are targeting iOS 5.0 I would read up upon ARC and the weak references it provides. If you don't want to use ARC, or need to target pre 5.x devices, I would recommend using zeroing weak reference libraries like MAZeroingWeakRef which work also for 3.x devices.
With either ARC's weak references or MAZeroingWeakRef, you would implement the background task with one of these fancy weak reference objects pointing back to your table. Now if the pointed object goes away, the weak pointer will nil itself and your background task won't crash.

Calling delegate method, unrecognized selector because sending to wrong object

In my app I do a lot of network loading. My data model consists of "Loader" objects that do this loading and call their delegate when finished/failed. The delegates all conform to a "LoaderDelegate" protocol.
The issue I'm having is that sometimes seemingly random objects, not the delegate, are getting the delegate messages. This of course causes a crash because of an unrecognized selector.
Only one set of crash logs tell me which one of my loaders is having the issue, the others don't have that information, just the random object that got the message.
I'm stuck at how to determine the real cause of this issue.
One set of crash logs has a loader trying to call it's delegate but reaching _UIImageViewExtendedStorage. Another has a loader is reaching __NSCFInputStream. Another __NSBlockVariable__. And yet another, CALayer.
And that's just in my latest beta from 3 days ago.
It would be one thing if it was the same object each time, but it seems almost random. Is it possible that memory is getting overritten with a new object somehow?
My delegate property for all of my loaders is an assign property, but the delegate is always alive when the loader finishes (delegates are my view controllers calling the loaders).
Please post some code, cause it is hard to troubleshoot. Remember to nil your delegate in the dealloc.
- (void) dealloc {
objectOfWhichIAmTheDelegate.delegate = nil;
}
What is more you the delegate should be an assign property not retain - but that's not a problem in your situation.
#property (assign) id<TheMightyDelegate> delegate;
Another thing you should do is to guarantee that the delegate responds to the selector you want to send to him before you fire the method.
if ([delegate respondsToSelector:#selector(yourMethod)]) {
[delegate performSelector:#selector(yourMethod)];
}
Hope this will put some light on your problem. If not please provide some code.
Turns out I was getting this error randomly all over the place, just not in this particular class and not just with delegate methods.
In my case, the problem turned out to be that I was accessing properties of various classes in multiple threads and those properties were nonatomic. Since I fixed that (removed nonatomic attribute of the properties), I haven't seen this happen anymore.

Checking for a valid delegate object before sending it a message

I am trying to implement the delegate Pattern in Objective-C, however I am experiencing a Bad Access exception when invoking the delegate sometimes. It seems this is caused by the delegate being released. Apple does not recommend to retain delegates.
How can I check my delegate if is still valid before trying to send it a message?
If there's a chance that the delegate will get released by the setter, then there's something wrong with your design. You should only set delegates on objects that have a shorter lifespan than the delegate itself. For example, setting a delegate on a subview/controller is fine, because the subview/controller has a shorter lifespan than the caller.
AFAIK, there is no reliable way to detect if an object has been released already.
What Apple means about not retaining delegates is that objects should not retain their delegates because they don't own them. These are only objects that handle messages.
That doesn't mean that you shouldn't retain delegates at all. The object that creates the delegate needs to own it. In the context of non-GC apps this means it should handle the retain and release cycle, and for GC apps, it means that the controller object keeps hold of a pointer to the delegate in an iVar.
without seeing some code or the error message, it is hard to find the root of this problem.
In a photoviewer application I'm using asynchronous http to load images; it happens that the user often dismisses the current view (referenced by my async http object through a delegate) before the http download completed causing a BAD_ACCESS when calling the view controller delegate method. I solved this by setting the .delegate to nil inside the dealloc block of the view controller
I'd like to share my experience also, which is very similar to Nico's one.
I've been working with a modified example of LazyTablesCode, wich is an example that comes direcly from Apple and loads images in a UITableView asynchronously. Communication between the downloader and the view it's made via delegates.
In my code, I had the problem that sometimes the load of the image finishes when the form that should be called through the delegate has been released. I've been forced to add this piece of code inside the code of the viewController (dealloc method):
if (self.nsDictionaryWithObjectsDownloading != nil) {
for (id theKey in self.nsDictionaryWithObjectsDownloading) {
Myobj *downloader = [self.nsDictionaryWithObjectsDownloading objectForKey:theKey];
downloader.delegate = nil;
}
}
It seems that these lines are solving the problem. Anyway It would be very appreciated opinions about if it's a good solution or not or even about memory issues when doing downloader.delegate = nil;
Thanks and greetings,