-
-
Save steipete/1521975 to your computer and use it in GitHub Desktop.
- (void) dealloc | |
{ | |
// dealloc can trigger in background thread when the queued block is | |
// our last owner, and releases us on completion. | |
// Send the dealloc back to the main thread so we don't mess up UIKit. | |
if (dispatch_get_current_queue() != dispatch_get_main_queue()) { | |
__block id block_self = self; // don't auto-retain self! | |
dispatch_async(dispatch_get_main_queue(), ^{ [block_self dealloc]; }); | |
} else { | |
[imageView release]; | |
[super dealloc]; | |
} | |
} |
What i'd love to know - is the object still valid when we're within a dealloc? Isn't that async calling on main thread dangerous (as the memory for the ivars might already be overwritten?) Or is there some more magic in NSObject dealloc?
I'd definitely turn this into a dispatch_sync
Dealloc is defined as the last step before an object is destroyed. Calling it again should not work. It is not responsible for destroying the object, it's just the last chance to handle stuff right before an other intern method destroys it. As always, correct me if I am wrong ;)
I think a nice solution would be for background threads to have a weak reference to the object. When they get scheduled they can turn the weak ref into a strong one, work with it and then schedule a [object release] on the main thread after they are done using it.
I've had to do code similar to this before and I think it's pretty safe but you have to be careful. It's safe in that your dealloc is obviously called before NSObject's as that happens when you call super (or going up the chain and ends up in NSObject) but I don't know if NSObject does anything else before calling dealloc. Would make a nice blog post to delve into this some more...
This code is buggy. I can't find the reference off the top of my head, but I'm pretty sure it is, or at least was, a rule that your dealloc method must be able to run from any thread. This is due to practical reasons- the order in which -releases and autorelease pool pops is non deterministic, and it would be an enormous burden on everyone if they had to follow some objects implementation requirement that it "only be -deallocd on a specific thread."
By simple first principles it should be obvious that this is broken- -dealloc can only be called when the retain count atomically drops to zero. At that point, since the retain count dropped to zero atomically, you are guaranteed by definition that there is no reference to this object anywhere in memory. It then follows that once the retain count has dropped to zero, it is "impossible" for the objects -retain method to be called. I say "impossible" because I don't think the language in Apples documentation is strong enough to say it's an error by definition, but I think it's pretty obvious that it is.
The technical term for this is "resurrection", and it is almost (always?) an indication of a fundamental bug somewhere.
I mean, honestly, who would be stupid enough to call -retain, or cause -retain to be called, from within -dealloc? Oh. Wait. Nevermind.
(it's non-ARC code)