Objective-C 学习 单例模式

文章目录

单例模式的使用

保证一个类在程序运行期间只创建一个对象,并提供一个全局访问入口。

单例模式有两个关键点:

  1. 只能创建一个对象实例
  2. 提供一个全局访问入口

单例要防止 3 种创建方式

  1. alloc
  2. copy
  3. mutablecopy

单例模式需要实现一个公共访问的类方法,一般命名为 shared + 类名。在该方法的具体实现方案,是推荐通过dispatch_once 来实现类的实例化。

可以直接通过重写父类的方法,把分配内存的方法变成只执行一次。从根本上实现了单例。

单例模式主要需要重写三个方法

objective-c 复制代码
+ (instancetype) allocWithZone: (struct _NSZone*) zone 
- (id) copyWithZone: (NSZone*) zone 
- (id) mutableCopyWithZone: (NSZone*) zone 

在 Objective-C 中,调用alloc方法时,底层确实会直接调用allocWithZone: ------alloc本质上是allocWithZone:的 "便捷封装"

objective-c 复制代码
static MyManager *_instance;
+ (instancetype)sharedInstance {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        _instance = [[super allocWithZone:NULL] init];
    });

    return _instance;
}

static保存唯一对象, 用dispatch_once 保证只创建一次

如果对象没有创建 -- > 创建

如果对象已经创建 -- > 直接返回

dispatch_once_t 类型的 onceToken 本质是一个状态变量,它存储着「代码块是否已经执行过」的信息:

  • 初始状态:onceToken 是一个特殊的默认值(可以理解为 "未执行");
  • 第一次执行 dispatch_once 时:系统会把 onceToken 的值修改为 "已执行",并执行代码块;
  • 后续执行 dispatch_once 时:系统检测到 onceToken 已是 "已执行" 状态,直接跳过代码块。
    instancetypeObjective-C 里的一个 返回类型关键字,表示:

返回当前类的实例类型。

它主要用于 方法返回对象时,让编译器更准确地知道返回的对象类型
为什么单例里要写

复制代码
[[super allocWithZone:NULL] init]

而不是

复制代码
[[self alloc] init]

这个其实是 防止递归死循环
Objective-C 的单例实现中,我们通常会重写 allocWithZone:。如果在 sharedInstance 里再调用 [self alloc],就会触发这个重写的方法,从而产生递归。

objective-c 复制代码
调用 sharedInstance
        ↓
[[self alloc] init]
        ↓
alloc
        ↓
allocWithZone
        ↓
return [self sharedInstance]
        ↓
再次进入 sharedInstance
        ↓
[[self alloc] init]
        ↓
allocWithZone
        ↓
...
objective-c 复制代码
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
} 

- (id)copyWithZone:(NSZone *)zone {
    return _instance;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    return _instance;
}

这段代码重写了allocWithZone: copyWithZone: mutableCopyZone: 三种方法, 很好理解,

直接返回唯一对象instance就可以了

完整代码如下:

objective-c 复制代码
@implementation MyManager

static MyManager *_instance;

+ (instancetype)sharedInstance {

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        _instance = [[super allocWithZone:NULL] init];
    });

    return _instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
} 

- (id)copyWithZone:(NSZone *)zone {
    return _instance;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    return _instance;
}

@end
相关推荐
海海不掉头发7 分钟前
【神经网络基础】-学习探索篇章-基础篇
人工智能·神经网络·学习
for_ever_love__8 分钟前
Objective-C学习:UI的初步了解
学习·ui·objective-c
weixin_4434785117 分钟前
Flutter第三方常用组件包学习之状态管理
javascript·学习·flutter
Engineer邓祥浩21 分钟前
JVM学习笔记(5) 第二部分 自动内存管理 第4章 虚拟机性能监控、故障处理工具
jvm·笔记·学习
读书札记202223 分钟前
1.单例模式
单例模式
woai336432 分钟前
JVM学习-基础篇-垃圾回收
java·jvm·学习
CDN36039 分钟前
iOS/Android 集成游戏盾审核被拒?权限与合规配置修复
android·游戏·ios
深蓝海拓41 分钟前
S7-1500学习笔记:Array数据类型
笔记·学习·plc
sun03222 小时前
旧版Ipad无法访问https的原因(不支持TLS1.3)
ios·https·ipad
Xudde.9 小时前
班级作业笔记报告0x04
笔记·学习·安全·web安全·php