方法调配用于以下单例初始化程序,但我不确定调度的线程安全性。
当一个线程要调用一个即将被另一个方法调整的方法时会发生什么? 在任何时候都可以安全地进行调整,而有线程即可调用该方法吗?请回答官方参考。感谢
#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
答案 0 :(得分:2)
我怀疑有关于此的官方参考,但不需要。
首先,该方法的可执行代码未从内存中取消映射。因此,安装哪个实现并不重要,先前的实现仍然可以执行。
但这确实意味着您必须确保您的数据管理是线程安全的(假设没有人试图直接调用sharedInstance_accessor
)。
因此,method_exchangeImplementations()
是否是线程安全的问题。 The source说它是(并且它不是之前的几个主要版本),文档也是如此。
正如Brad Allred所说,这不太可能是值得追求的优化。
答案 1 :(得分:1)
根据documentation,method_exchangeImplementations()
是原子的。据推测,这意味着如果在运行method_exchangeImplementations()
的同时从另一个线程调用正在交换的两个方法之一,它可能会获得先前的(非交换的)方法,但它不会得到某些东西不一致(例如不会崩溃)。
请注意dispatch_once()
是线程安全的,也意味着只要通过+sharedInstance
获得对单例实例的所有引用,在完成混合之前,任何线程都不会引用该对象。
最后,我通常不喜欢将这类内容添加到答案中,因为我意识到有时候提问者只是试图更多地了解事情是如何运作的,而不是试图编写生产代码。但是,如果您打算在真实的运输代码中使用它,您应该重新考虑它。调酒往往是一种“糟糕的代码味道”,并且可能有更好的方法来做你想要完成的任何事情(我仍然不清楚)。