Does ARC insert code in -dealloc before or after any custom -dealloc code? - iphone

With ARC sometimes I still need to write a -dealloc method to do some cleanup. In some rare cases I need to refer to properties of the instance to properly do cleanup. Such as unregistering from NSNotificationCenter with a given sender object, which is owned and referenced by a property.
Does ARC insert it's property release code at the end of after my own code, or does it insert this at the beginning of -dealloc, before my own code?
If ARC would be inserting code before any custom -dealloc code, then this would be very dangerous since you can't access properties anymore if needed.
This question is about where ARC inserts the property release code in a synthesized -dealloc, and not about wether or not to implement -dealloc.

I think, that everything is said here: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#misc.special_methods.dealloc
7.1.2. dealloc
A program is ill-formed if it contains a message send or #selector expression for the selector dealloc.
Rationale: there are no legitimate reasons to call dealloc directly.
A class may provide a method definition for an instance method named dealloc. This method will be called after the final release of the object but before it is deallocated or any of its instance variables are destroyed. The superclass's implementation of dealloc will be called automatically when the method returns.
Rationale: even though ARC destroys instance variables automatically, there are still legitimate reasons to write a dealloc method, such as freeing non-retainable resources. Failing to call [super dealloc] in such a method is nearly always a bug. Sometimes, the object is simply trying to prevent itself from being destroyed, but dealloc is really far too late for the object to be raising such objections. Somewhat more legitimately, an object may have been pool-allocated and should not be deallocated with free; for now, this can only be supported with a dealloc implementation outside of ARC. Such an implementation must be very careful to do all the other work that NSObject's dealloc would, which is outside the scope of this document to describe.

ARC releases instance variables at the end of the dealloc chain. In other words, all the dealloc methods in the inheritance chain are run, and then any ARC-managed instance variables will be deallocated. You could think of it as happening in -[NSObject dealloc], though it's really even later than that.
So rest assured; ARC won't release your properties out from under you in your -dealloc method. ARC won't release them until you have no way to reference them anymore.

Related

ARC delegate issue

I need to download some images from server. So I created a seperate class to handle NSURLConnection delegates.
At the end of didFinishDownloadingData, I called a delegate method like [(id)delegate performSelectorselector(finished:) withObject:receivedData]
I have a view controller called ListImages.
I created the above connection class from ListImages class and assigned connection.delegate = self. After image loaded from server the method -(void)didFinishDownloadingData:(NSData *)data; was called successfully, and I could display that image.
My problem starts now. To handle some common tasks, I created a new class called SharedMethods which is a subclass of NSObject. I allocated connection class as
Connection *conn = [[Connection alloc]init];
conn.delegate = self;
[conn startDownload]; //called a method which starts nsurlconnection.
I am using ARC so not released that object. My applicaion got exception in method, (In Connection class)
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[(id)delegate performSelectorselector(finished:) withObject:receivedData]; //Got an exception in this line
}
The exception was [SharedMethods retain] message send to deallocated object. I dont think I have released anything because I am using ARC.
There was also a problem while callingUIAlerView delegates inside a Class which is a subclass of NSobject. It is not called any how. My doubt is, is there any problem with using a NSObject sublass? Is there anything to consider when using NSObject sublass ?
Thanks in advance.
Using ARC doesn't mean than objects never receive the release method, or that they never get deallocated. It just means that you don't have to make explicit calls to retain and release, and that happens automatically.
The problem here is that your objects are getting deallocated because no one is owning them. Your specific problem is that SharedMethods is being deallocated because it's not getting retained, but I can't show you how exactly that's happening because you didn't post the relevant code.
I can, however, show you that you're not managing your Connection properly, and hopefully that can help you figure out what you're doing wrong with SharedMethods.
So you create Connection with alloc init, which with retain-release code would give it a retain count of 1, but since you're not using ARC anymore that's not really relevant. Unless some other object asserts ownership of the Connection, ARC will automatically insert a call to release to bring the retain count back to 0 (it's kind of like if ARC automatically inserted an autorelease).
Since you don't assign Connection to a strong or retain property, or put it in a collection, no other object is asserting ownership to it. So once execution reaches the end of the scope where the variable conn is defined, it will get released and deallocated.
So in ARC, much like in manual retain-and-release code, you still need to make sure objects are owned by some other object in order for them to stick around. The only difference is that you don't need to manually call retain and release, you just have to think about the object ownership graph—which object is owned by which other object—and make sure that any object you want to stick around is owned by some other object.
So to reiterate, you need make sure that SharedMethods is owned by some other object.

What's the equivalent of '[[something retain] autorelease]' in ARC?

What's the equivalent of [[something retain] autorelease] in ARC?
I have a problem where a class DBRequest calls my delegate to signify completion. My delegate then sets the DBRequest instance to nil, which dealloc's it. But then when the stack pops out of my delegate and jumps back to the DBRequest, it of course then crashes.
If I wasn't in ARC, in my delegate I'd simply do [[theDbRequest retain] autorelease] before releasing my reference to it, so that it'd survive long enough until the next run loop autoreleased it.
What should I do in ARC?
How about adding something like
__strong DBRequest * myself = self;
[delegate reportDone];
I think that'll increment the self object until the end of the function preventing it from dying early.
My delegate then sets the DBRequest instance to nil, which dealloc's it. But then when the stack pops out of my delegate and jumps back to the DBRequest, it of course then crashes.
Surely this was always a bad strategy, and your [[theDbRequest retain] autorelease] was always just covering up the problem, yes?
Simply do nothing. So your instance variable sticks around; so what? You know that ARC will release it for you when you are dealloced.
The important thing is not to release theDbRequest, but to set theDbRequest's reference to you (the delegate) to nil, so it doesn't try to call you back when you no longer exist. Your own dealloc would be a good place to do that.
Hope I'm understanding the issue correctly. If not, post some code!
As #matt says if you simply do nothing ARC should clean up when your object is deallocated - assigning the DBRequest you create to an instance variable handles that (provided of course your object outlasts the object you are creating).
If you need to deallocate the DBRequest before your object dies then you need an ARC-compatible "trick" equivalent to [[theDbRequest retain] autorelease]. Now unless you are constructing your own auto release pools your previous approach would trigger at the end of the current event. Following that logic try:
Add a method to your class which simply sets theDbRequest to nil, let's call this cleanUpTheDbRequest.
Change your delegate callback to invoke [self performSelectorOnMainThread:#selector(cleanUpTheDbRequest) withObject:nil waitUntilDone:NO] instead of directly assigning nil to theDbRequest
This should delay the assigning of nil till after the end of the current event, just as your autorelease "trick" did. It also works if your DBRequest lives across multiple events - the previous method kicks in at the end of the event the autorelease is called in, this method at the end of the event the delegate method is called in.

Assigning ivars using self keyword in an object's init method

I've read that it's bad to use self.ivar = (convenience method) in and object's 'init' method, as this messes with inheritance.
However, if you know you're not going to subclass your object, is it ok to use the self keyword assignment?
i.e. self.iVar = [Object objectConvenienceMethod];
The reason I ask is this. I create a new object with its own init method, and in that method, I perform various initial assignments. Since I don't use the self keyword, I assign them directly to the iVars, and therefore use the alloc methods rather than the convenience methods. I.e.
iVar = [[Object alloc] init];
Or if I use a convenience method, I retain it. I.e.
iVar = [[Object convenienceMethod]retain]
But... when I run my program with the memory leak tool on, all of these assignments are identified as memory leaks.
If I can use the self keyword plus a convenience method instead of alloc-init, then this would avoid the problem.
If I choose to use the alloc-init approach though, where am I supposed to release the iVars?? Just in dealloc?
Thanks for your help :)
Michael
No, because it isn't only subclass behavior you need to take into account — superclass implementations and even the behavior of code generated by the framework (e.g. synthesized accessors and the black magic used to implement KVO) can also cause trouble. It will probably be OK, but that's still a significant chance of being not-OK. All in all, it's best just to follow Apple's recommendation and assign directly.
Assigning to ivars in init shouldn't be reported as leaks in a properly functioning program. If you're seeing that, there's some other problem that you need to address. Try reducing the problem to a minimal case that we can try out and ask about that — then we can tell what's wrong.
If you alloc or retain them in your class's init method, you should release them in the corresponding dealloc method.
I am thinking your "enclosing" class is not being released, and hence its dealloc method is not being called resulting in your iVars not being released.

Do I need to explicitly alloc my NSNumber?

I am defining a number, as follows:
NSNumber *nn0 = [NSNumber numberWithInt:0];
It works fine without any alloc. My understanding is that if I use numberWithInt, alloc and init are called automatically.
If I try to release at the end of my function, I run into problems:
[nn0 release];
I get a runtime error.
My question is: if I use numberWithInt to initialise the NSNumber, do I have to do any memory management on it?
The "convenience constructors" for a lot of types produce an object that is automatically "autoreleased" - i.e. the new object will be retained by the current NSAutoreleasePool. You don't need to manually release these objects - they will be released when the current NSAutoreleasePool is released/drained.
See this page for a description of convenience constructors, and how to mange the memory for these.
http://www.macdevcenter.com/pub/a/mac/2001/07/27/cocoa.html?page=3
Just follow the core memory-management rule: If you "own" the variable, you have to eventually relinquish ownership. You take ownership by: creating the object (alloc/new/copy) or specifically taking ownership (retain). In all these cases, you're required to release it.
If you need the object to stick around, you need to take ownership of it. So if you know you only need the number for this method (like to pass it into an array or whatever), use the convenience method and just leave it at that. If you want to keep the number for some reason (and instance variable, for example), then you can safely alloc/init it.
If you release something that you don't own, you will get a runtime error.
The rule is simple, with very few exceptions:
If the selector returning an object has the word "new", "alloc", "retain" or "copy" in it, then you own the returned object and are responsible for releasing it when you are finished.
Otherwise you do not own it and should not release it. If you want to keep a reference to a non-owned object, you should call -[NSObject retain] on that instance. You now "own" that instance an must therefore call -[NSObject release] on the instance when you are done with it. Thus you do not own the instance returned by -[NSNumber numberWithInt:] and should not call -release on it when you are done. If you want to keep the returned instance beyond the current scope (really beyond the lifetime of the current NSAutoreleasePool instance), you should -retain it.
In RegEx terms, Peter Hosey lays it out very nicely in his blog. You own the returned object instance if the method selector matches this regex:
/^retain$|^(alloc|new)|[cC]opy/
Of course, the definitive reference is the Memory Management Programming Guide for Cocoa.

What explains best the difference between [myVar dealloc] and [myVar release]?

I think I know the difference, but don't know how to explain that correctly.
dealloc removes the memory reserved by that variable totally and immediately.
release decrements the retain counter of that variable's memory by -1. if it was 1, then it's 0, so it would have the same effect as dealloc in that moment.
is that right? or is there an better short explanation?
That's exactly right.
But you wouldn't use dealloc, when using an object, because you don't know what the retain count is. Nor do you care. You just say that you don't need it anymore, by calling release. And once nobody does, the object will call dealloc on itself.
All correct, but the one key point you're missing is that you should never call dealloc yourself. Here's some information from Apple's documentation on NSObject's dealloc method:
(from http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/dealloc)
You never send a dealloc message
directly. Instead, an object’s dealloc
method is invoked indirectly through
the release NSObject protocol method
(if the release message results in the
receiver's retain count becoming 0).
See Memory Management Programming
Guide for Cocoa for more details on
the use of these methods.
Subclasses must implement their own
versions of dealloc to allow the
release of any additional memory
consumed by the object—such as
dynamically allocated storage for data
or object instance variables owned by
the deallocated object. After
performing the class-specific
deallocation, the subclass method
should incorporate superclass versions
of dealloc through a message to super: