方法swizzling在下面的singleton初始值设定项中使用,但我不确定swizzling的线程安全性。
当一个线程即将调用一个即将被另一个方法刷新的方法时,会发生什么?当有线程要调用该方法时,在任何时候都可以安全地进行swizzle吗?请用官方参考资料回答。感谢
#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
我怀疑是否有官方参考,但不需要。
首先,该方法的可执行代码不是从内存中取消映射的。因此,安装哪个实现并不重要,之前的实现仍然可以执行。
然而,这确实意味着,您必须确保您的数据管理是线程安全的(假设没有人试图直接调用sharedInstance_accessor
)。
这就留下了一个问题,即method_exchangeImplementations()
是否是线程安全的。消息人士表示,这是(而且之前不是几次主要发布),文档也是如此。
正如Brad Allred所说,这不太可能是一个值得追求的优化。
根据文档,method_exchangeImplementations()
是原子的。这可能意味着,如果在运行method_exchangeImplementations()
的同时,从另一个线程调用正在交换的两个方法中的一个,它可能会得到上一个(非交换的)方法,但不会得到不一致的东西(例如不会崩溃)。
注意,dispatch_once()
是线程安全的,这也意味着只要对singleton实例的所有引用都是通过+sharedInstance
获得的,那么在swizzling完成之前,没有线程会引用该对象。
最后,我通常不喜欢在答案中添加这种东西,因为我意识到,有时提问者只是想了解更多关于事物如何工作的信息,而不是试图编写生产代码。然而,如果你打算在真实的运输代码中使用它,你应该重新考虑;坏代码气味";,而且很可能有更好的方法来做你想要完成的事情(我仍然不清楚)。