文章目录
- 单例模式的使用
- 单例模式有两个关键点:
- 单例要防止 3 种创建方式
- 完整代码如下:
单例模式的使用
保证一个类在程序运行期间只创建一个对象,并提供一个全局访问入口。
单例模式有两个关键点:
- 只能创建一个对象实例
- 提供一个全局访问入口
单例要防止 3 种创建方式
- alloc
- copy
- mutablecopy
单例模式需要实现一个公共访问的类方法,一般命名为 shared + 类名。在该方法的具体实现方案,是推荐通过dispatch_once 来实现类的实例化。
可以直接通过重写父类的方法,把分配内存的方法变成只执行一次。从根本上实现了单例。
单例模式主要需要重写三个方法
+ (instancetype) allocWithZone: (struct _NSZone*) zone - (id) copyWithZone: (NSZone*) zone - (id) mutableCopyWithZone: (NSZone*) zone在 Objective-C 中,调用alloc方法时,底层确实会直接调用allocWithZone:——alloc本质上是allocWithZone:的 “便捷封装”
staticMyManager*_instance;+(instancetype)sharedInstance{staticdispatch_once_t onceToken;dispatch_once(&onceToken,^{_instance=[[superallocWithZone:NULL]init];});return_instance;}static保存唯一对象, 用dispatch_once 保证只创建一次
如果对象没有创建 – > 创建
如果对象已经创建 – > 直接返回
dispatch_once_t类型的onceToken本质是一个状态变量,它存储着「代码块是否已经执行过」的信息:
- 初始状态:
onceToken是一个特殊的默认值(可以理解为 “未执行”);- 第一次执行
dispatch_once时:系统会把onceToken的值修改为 “已执行”,并执行代码块;- 后续执行
dispatch_once时:系统检测到onceToken已是 “已执行” 状态,直接跳过代码块。
instancetype是Objective-C里的一个返回类型关键字,表示:返回当前类的实例类型。
它主要用于方法返回对象时,让编译器更准确地知道返回的对象类型。
为什么单例里要写
[[super allocWithZone:NULL] init]而不是
[[self alloc] init]这个其实是防止递归死循环
在Objective-C的单例实现中,我们通常会重写
allocWithZone:。如果在sharedInstance里再调用[self alloc],就会触发这个重写的方法,从而产生递归。调用 sharedInstance ↓[[selfalloc]init]↓ alloc ↓ allocWithZone ↓return[selfsharedInstance]↓ 再次进入 sharedInstance ↓[[selfalloc]init]↓ allocWithZone ↓...
+(instancetype)allocWithZone:(struct_NSZone*)zone{return[selfsharedInstance];}-(id)copyWithZone:(NSZone*)zone{return_instance;}-(id)mutableCopyWithZone:(NSZone*)zone{return_instance;}这段代码重写了allocWithZone:copyWithZone:mutableCopyZone:三种方法, 很好理解,
直接返回唯一对象instance就可以了
完整代码如下:
@implementationMyManagerstaticMyManager*_instance;+(instancetype)sharedInstance{staticdispatch_once_t onceToken;dispatch_once(&onceToken,^{_instance=[[superallocWithZone:NULL]init];});return_instance;}+(instancetype)allocWithZone:(struct_NSZone*)zone{return[selfsharedInstance];}-(id)copyWithZone:(NSZone*)zone{return_instance;}-(id)mutableCopyWithZone:(NSZone*)zone{return_instance;}@end