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
相关推荐
cola_wh2 小时前
避免团队多人 cocopods 冲突未验证
ios
2501_915921432 小时前
在 Linux 上通过命令行上架 iOS APP,Fastlane + AppUploader(开心上架)
android·linux·运维·ios·小程序·uni-app·iphone
WJSKad12352 小时前
Ghost瓶颈轻量化改进YOLOv26双路径特征生成与残差学习协同突破
学习·yolo
张永清-老清2 小时前
每周读书与学习->Jmeter中如何使用Bean Shell脚本(二)Bean Shell的基础语法之变量与数据类型
学习·测试工具·jmeter·压力测试·性能调优·jmeter性能测试·性能分析
食指Shaye2 小时前
docker的学习日记
学习·docker·eureka
科技林总2 小时前
【系统分析师】11.3 软件需求获取
学习
盐水冰2 小时前
【烘焙坊项目】后端搭建(7)- 套餐管理界面
java·学习
2501_915921432 小时前
从构建到 IPA 保护,Flutter iOS 包如何做混淆与安全处理
android·安全·flutter·ios·小程序·uni-app·iphone
小红卒2 小时前
Go语言安全开发学习笔记5:tls反弹shell升级到C2指令执行马
笔记·学习·网络安全·golang