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
相关推荐
lwf0061643 分钟前
梯度学习日记
学习·机器学习
米奇妙啊妙11 分钟前
agent 学习 -模拟AI调用工具
人工智能·学习
试剂界的爱马仕19 分钟前
AI学习实现:如何给基金实时估值?
大数据·人工智能·科技·学习·机器学习
报错小能手32 分钟前
Swift EventBus讲解
开发语言·ios·swift
2301_792674861 小时前
java学习day31(redis)
java·redis·学习
xuhaoyu_cpp_java1 小时前
MyBatis学习(一)
java·经验分享·笔记·学习·mybatis
爱上好庆祝2 小时前
学习js的第三天
前端·css·人工智能·学习·计算机外设·js
前端摸鱼匠2 小时前
【AI大模型春招面试题29】对比学习(Contrastive Learning)在大模型预训练中的应用?
人工智能·学习·算法·面试·大模型·求职招聘
一尘之中2 小时前
星空彼岸:科学、宗教与“超越”的可能
学习·ai写作
三品吉他手会点灯2 小时前
C语言学习笔记 - 16.C编程预备计算机专业知识 - Hello World程序的运行原理
c语言·笔记·学习