Programmatically determine if a Cocoa object loaded from nib/xib is available - objective-c

The setting is the following:
I have a cocoa object in a nib file that is loaded when the NSWindow and view is loaded
The window can be closed
I also access the object programmatically
Now what happens in some situations is that I get a crash, when I try to send a message to the object, but it has been deallocated before (because the window is closed). The crash looks like this:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000017
Crashed Thread: 0
Dispatch queue: com.apple.main-thread
Application Specific Information:
objc_msgSend() selector name: ...
Is there any way to check if the object is available or not? Checking for nil does not work, it is not nil. Probably the control flow is not perfect, and I could rewrite other chunks of the app to make this problem go away, but I think this is a more general problem that I have no solution for, and it boils down to this:
How can I make sure that an object that is loaded from a nib is set to nil on deallocation?

I guess you could use Interfacebuilder to write your Window-class and in its dealloc method you could set the VARIABLE to nil. But you cannot set the object itself to nil. the variable saves a pointer to the object, if its deallocated the pointer points to a place in memory where anything could be.
So if you access said object from another class, you have another variable, so setting the one in your windows-class to nil, wouldnt be useful at all.
The solution is quiet simple, since the window-class sends this object a release message when the window get deallocated, you should retain your object bevor you use it in another class, and then release it when youre done with it.
If you use a property for your object with the retain-attribute dont forget to call the setter with self.object = ... without property it could look sth like this:
so you need to retain your object bevor the window gets closed. maybe in the first viewDidLoad-method that gets called by your app:
...
- (void)viewDidLoad {
otherClassObject.YOUROBJECT = [self.YOUROBJECT retain];

Try deactivating the window setting "Release when close" on Interface Builder.

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.

Request traitement crash - Message sent to deallocated instance

I'm executing an asynchronous method on an object and when my request is finish I print the result in a label. My problem is : if I launch my request and then I remove my object, I have a crash on my setText method (because my object is deallocated).
How can I avoid this crash even if my object has been released ?
Is there any test to do ?
1) Don't remove your object until the request is finished :)
2) Cancel the request (not always possible depending on your object)
The solution is to have a NSMutableArray object created in you "init" or in your "viewDidLoad" method. When you want to remove the object, always put it in this array after removing it from its superview. Then in your asynchronous method (which better be running on the main thread to print the result), the last thing it does is [storageArray removeObject:object], to release it.
If your object is deallocated and its currently a subview on a view, then the view itself has been destroyed, you have nowhere to display the label contents. Why this would be depends on the design of your app, but usually the removal of a view is detectable by your code and you should set any references to the view to nil in that case if you know its gone.
If the label hasnt been added to the view yet - then you needed to retain the label, so that you can set the text on it and call addSubview on the containing view.
Also if a user action would be causing the view to be removed - display a spinner and block the user from doing this since a request they invoked is in progress.
The asynchronous request can retain the object until it's done with it.

dealloc is being called and I am not sure why

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.

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,