Skip to content

oldratlee/objc-singleton

Repository files navigation

Objective C Singleton

👉 实现安全Objective C Singleton

🍺 关于安全

“安全”是指:

  1. 多线程安全
  2. 使用安全,即通过new类方法、init方法仍然返回的是同一个单例对象。new/init方法不做处理用户是可以调用的。

第二点在场景上看起来有些吹毛求疵,用户可以粘贴示例代码或是看一下文档可以做到通过工厂方法获得单例,规避这个问题。

在各篇Objective C Singleton文章中这方面几乎都没有得到重视,但对于API的用户防痴呆设计上是有意义的。

关于API设计

  • 只有几人两三应用使用的API,不要谈API设计重要或复杂。
    这种情况下,积极感受问题跟进改进API看起来更有性价比。
  • 没写给成百上千人上百应用使用的API,不要谈API设计不重要或复杂。
    这种情况下,一个细微的改进能省下支持工作,并值得提高用户的体验和用户对产品的评价。

解决线程安全

有以下方案:

  1. 通过+ (void)initialize
  2. 通过@synchronized
  3. 通过GCDdispatch_once。这个方案比上一个更现代,性能也更优。

解决使用安全

在非ARC的实现,能保证使用安全,参见UT代码

ARC的实现中,没有解决这个问题。参见UT代码

详见如何禁止一个方法的外部调用来做些补救。

🍺 使用宏简化Singleton实现

单例的实现是很模板化,了解上面的实现方案和关注点后,可以通过宏自动生成单例类实现,这样可以

  • 保证实现的安全
  • 避免重复的体力劳动

宏实现参见SynthesizeSingleton.h

🍺 相关资料

Objective C Singleton文章

涉及的资料

如何禁止一个方法的外部调用

编译时

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

如何关闭指定文件的ARC

官方文档及源码

About

How to implement a SAFE Objective-C Singleton

Resources

Stars

Watchers

Forks