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
相关推荐
无敌贵点大王1 小时前
RTThread学习记录11——RT-Thread 设备模型吃透:UART/ADC/PWM/PIN 到底有什么区别?
c语言·stm32·学习·链表
2501_915918412 小时前
iOS编程用什么软件好?主流工具Xcode、AppCode、CodeRunner与新兴快蝎对比
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
是翎2 小时前
深度长文|2026产品经理AI实践手册
人工智能·深度学习·学习·自然语言处理·数据挖掘
Linux-lucky3 小时前
32-38-Linux学习之旅之MySQL综合
linux·运维·学习·mysql·ubuntu
知识分享小能手4 小时前
C++ 学习教程,从入门到精通,C++ 入门知识 — 完整知识点(1)
开发语言·c++·学习
AI职业加油站6 小时前
数据要素价值释放年:大数据治理工程师,站上职业新风口
人工智能·学习·职场和发展·数据分析·职场发展
啄缘之间7 小时前
1.【SVA】什么是SVA?
经验分享·学习·测试用例·verilog·sva
sunoo-2298 小时前
【嵌入式裸机开发Day04】i.MX6ULL 蜂鸣器驱动详解:从引脚地址查找到代码实现全流程
arm开发·单片机·嵌入式硬件·学习·串口·裸机
Purple Coder8 小时前
stm32
学习
边境悍匪8 小时前
蜗牛学苑 Java 智能体学习 Day45|Knife4j+SpringBoot3、书城项目整合 MyBatis 思维导图复盘
java·开发语言·vue.js·学习·spring