👉 实现安全的Objective C
Singleton
。
“安全”是指:
- 多线程安全
- 使用安全,即通过
new
类方法、init
方法仍然返回的是同一个单例对象。new
/init
方法不做处理用户是可以调用的。
第二点在场景上看起来有些吹毛求疵,用户可以粘贴示例代码或是看一下文档可以做到通过工厂方法获得单例,规避这个问题。
在各篇Objective C
Singleton
文章中这方面几乎都没有得到重视,但对于API
的用户防痴呆设计上是有意义的。
关于
API
设计:
- 只有几人两三应用使用的API,不要谈API设计重要或复杂。
这种情况下,积极感受问题跟进改进API看起来更有性价比。- 没写给成百上千人上百应用使用的API,不要谈API设计不重要或复杂。
这种情况下,一个细微的改进能省下支持工作,并值得提高用户的体验和用户对产品的评价。
有以下方案:
- 通过
+ (void)initialize
。 - 通过
@synchronized
。 - 通过
GCD
的dispatch_once
。这个方案比上一个更现代,性能也更优。
在非ARC
的实现,能保证使用安全,参见UT代码。
ARC
的实现中,没有解决这个问题。参见UT代码。
详见如何禁止一个方法的外部调用来做些补救。
单例的实现是很模板化,了解上面的实现方案和关注点后,可以通过宏自动生成单例类实现,这样可以
- 保证实现的安全
- 避免重复的体力劳动
宏实现参见SynthesizeSingleton.h。
- Singletons in Objective-C
- 通过
GCD
的dispatch_once
的线程安全实现 - 包含
ARC
和 非ARC
的实现
- 通过
- Objective-C中单例模式的实现
- 讨论了苹果的文档的实现 和
GCD
的dispatch_once
线程安全实现 - 给出生成单例实现类的宏
- 讨论了苹果的文档的实现 和
- Objective-C中单例模式(Singletons)的实现
- 通过
GCD
的dispatch_once
和@synchronized
的线程安全实现 - 非
ARC
的实现
- 通过
- What should my Objective-C singleton look like? - stackoverflow.com
- 通过
+ (void)initialize
的线程安全实现
- 通过
- Objective-C singleton macros
- 生成单例实现类的宏
- 会根据编译参数是否
ARC
,生成不同实现类!
- Avoiding Singleton Abuse - objc.io,单例使用注意。
Singleton Implementation. Blocking the alloc and init methods for external usage | Create singleton using GCD's dispatch_once in Objective C提到了一个如何禁止方法在外部调用的方法,即设置方法只能类实现中调用。
通过__attribute__ unavailable
可以让指定方法的外部直接调用在编译时报错且给出错误信息:
- (id)init __attribute__((unavailable("cannot use init for this class, use +(MYClass*)sharedInstance instead")));
由于__attribute__ unavailable
是在编译时的检查,所以不能阻止运行时的动态调用。
如在Class
变量上进行调用(这点在UT实现代码可以编译通过得到验证):
id instance = [[clazz alloc] init];
关于__attribute__
详见Attributes in Clang
通过override
方法实现成抛异常,可以保证运行时禁止方法调用。参见Create singleton using GCD's dispatch_once in Objective C。
- How can I disable ARC for a single file in a project?
- Disable Automatic Reference Counting for Some Files
- 官方文档:Objective-C Automatic Reference Counting (ARC),ARC的编译选项说明。
- Attributes in Clang,
__attribute__
说明 - NSObject.mm源码 - opensource.apple.com
- NSNull.m源码