Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is dealloc guaranteed to be called on the same thread that created the object?

Tags:

objective-c

Is dealloc guaranteed to be called on the same thread that created a NSObject instance? For example, if I call [[MyFluffyBunny alloc] init] on the main thread, is dealloc guaranteed to also be called on the main thread, or can it be called on any thread once MyFluffyBunny is no longer retained?

I see sporadic crashes in my app that points to that it's not guaranteed, but I've been unable to find any documentation confirming it.

like image 462
Claus Jørgensen Avatar asked Sep 26 '15 17:09

Claus Jørgensen


2 Answers

The object is deallocated on whatever thread releases the last strong reference to it. That is, whatever thread calls -release the final time. It is actually during that -release call that the object is deallocated.

The documentation for the -release method in the NSObject protocol says:

Decrements the receiver’s reference count. … The receiver is sent a dealloc message when its reference count reaches 0.

The Advanced Memory Management Programming Guide: Practical Memory Management article includes this among the reasons to not use -dealloc to manage scarce resources:

  1. Cleanup logic being executed on the wrong thread.

    If an object is autoreleased at an unexpected time, it will be deallocated on whatever thread’s autorelease pool block it happens to be in. This can easily be fatal for resources that should only be touched from one thread.

like image 192
Ken Thomases Avatar answered Sep 21 '22 04:09

Ken Thomases


There is no such guarantee and, in fact, it makes for some subtle bugs when using KVO (and bindings on OS X).

You can see it in action fairly easily by creating an object that logs [NSThread currentThread] during init and dealloc, then running code such as:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    Testing *testing = [[Testing alloc] init];
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
        NSLog(@"Use testing in background: %@", testing);
    });
    testing = nil;
    return YES;
}
like image 34
Phillip Mills Avatar answered Sep 20 '22 04:09

Phillip Mills