lockedscope
lockedscope

Reputation: 983

Thread-safety of method swizzling

Method swizzling is used in the following singleton initializer but i am not sure about thread safety of swizzling.

What happens while a thread is about to call a method which is about to be swizzled by another method? Is it safe to swizzle in any time, while there are threads about to call that method? Answer with official references please. Thanks

#import <dispatch/dispatch.h>
#import <objc/runtime.h>

@implementation MySingleton

static MySingleton * __singleton = nil;

+ (MySingleton *) sharedInstance_accessor
{
    return ( __singleton );
}

+ (MySingleton *) sharedInstance
{
    static dispatch_once_t __once = 0;

    dispatch_once( &__once, ^{ 
                __singleton = [[self alloc] init]; 
        Method plainMethod = class_getInstanceMethod( self, @selector(sharedInstance) );
        Method accessorMethod = class_getInstanceMethod( self, @selector(sharedInstance_accessor) );
        method_exchangeImplementations( plainMethod, accessorMethod );
        });
    return ( __singleton );
}

@end

https://gist.github.com/MSch/943369

Upvotes: 1

Views: 597

Answers (2)

Andrew Madsen
Andrew Madsen

Reputation: 21373

According to the documentation, method_exchangeImplementations() is atomic. Presumably that means that if one of the two methods being exchanged is called from another thread at the same time as method_exchangeImplementations() is being run, it may get the previous (non-swapped) method, but it won't get something inconsistent (e.g. won't crash).

Note that dispatch_once() is thread safe, and also means that as long as all references to the singleton instance are obtained via +sharedInstance, no thread will have a reference to the object before the swizzling is complete.

Finally, I don't normally like adding this kind of thing to answers, because I realize that sometimes questioners are just trying to learn more about how things work, rather than trying to write production code. However, if you're planning to use this in real, shipping code, you should rethink it. Swizzling tends to be a "bad code smell", and it's likely that there's a better way to do whatever it is you're trying to accomplish (which is still not clear to me).

Upvotes: 1

bbum
bbum

Reputation: 162712

I doubt there is an official reference on this, but none is needed.

First, the executable code of the method is not un-mapped from memory. Thus, it doesn't matter which implementation is installed, the prior implementation is still available for execution.

That does mean, however, that you have to ensure that your data management is thread safe (which it is, assuming no one tries to call sharedInstance_accessor directly).

So that leaves a question as to whether method_exchangeImplementations() is thread safe. The source says it is (and it was not several major release prior) and so does the documentation.

As Brad Allred said, this is unlikely to be an optimization worth pursuing.

Upvotes: 2

Related Questions