1

方法 swizzling 用于以下单例初始化程序,但我不确定 swizzling 的线程安全性。

当一个线程即将调用一个即将被另一个方法调动的方法时会发生什么?在有线程要调用该方法的情况下,随时进行调配是否安全?请用官方参考回答。谢谢

#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

4

2 回答 2

2

我怀疑对此是否有官方参考,但不需要。

首先,该方法的可执行代码不是从内存中映射的。因此,安装哪个实现并不重要,之前的实现仍然可以执行。

但是,这确实意味着您必须确保您的数据管理是线程安全的(假设没有人尝试sharedInstance_accessor直接调用)。

所以这就留下了一个关于method_exchangeImplementations()线程是否安全的问题。消息来源说它是(并且它不是之前的几个主要版本),文档也是如此。

正如 Brad Allred 所说,这不太可能是值得追求的优化。

于 2013-11-30T16:25:43.290 回答
1

根据文档method_exchangeImplementations()是原子的。据推测,这意味着如果正在交换的两个方法之一在method_exchangeImplementations()运行的同时从另一个线程调用,它可能会获得前一个(非交换)方法,但它不会得到不一致的东西(例如不会' t 崩溃)。

请注意,这dispatch_once()是线程安全的,也意味着只要对单例实例的所有引用都是通过 获得+sharedInstance的,那么在 swizzling 完成之前,没有线程会引用该对象。

最后,我通常不喜欢在答案中添加这种东西,因为我意识到有时提问者只是想更多地了解事情是如何工作的,而不是尝试编写生产代码。但是,如果您打算在实际的运输代码中使用它,您应该重新考虑它。Swizzling 往往是一种“糟糕的代码气味”,很可能有更好的方法来完成你想要完成的任何事情(我仍然不清楚)。

于 2013-11-30T16:22:37.517 回答