当前位置: 首页 > article >正文

【iOS】单例模式

目录

  • 前言
  • 单例模式
    • 认识单例模式
    • 单例模式的特点及使用情景
    • 单例模式的使用
      • 单例模式的实现步骤:
      • 完整代码
  • 总结

前言

  在进行大项目编写之前,开始对前面比较重要的知识进行回顾和重新学习,单例模式在软件开发设计中是比较重要的,尤其是它的初始化,笔者重新学习了单例模式并作该笔记。

单例模式

认识单例模式

在百度中,单例模式的定义如下:

数学与逻辑学中,singleton定义为“有且仅有一个元素的集合”。 单例模式最初的定义出现于《设计模式》(艾迪生维斯理, 1994):“保证一个类仅有一个实例,并提供一个访问它的全局访问点。”
Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”

在OC中,单例模式(Singleton Pattern)也如此,其核心目的是确保一个类只有一个实例,并提供一个全局访问点来获取这个实例

关于对单例模式更通俗易懂的解释,我读到掘金上的一篇文章是这样举例的:

如果说每一个人都是一个类,那么从他出生开始,他就是生活中的唯一实例,每当有人要拜访或者联系你的时候,无论别人认识你的时候你是什么状态,他所能联系到的都是现在的你。你本身的状态会在其他地方发生改变,即当你状态改变后,后续所有找到你的,都是看到状态改变后的你。那么,我们就可以认为每一个人都处于单例模式。

在OC中,最经典的单例模式就是xcode里自带的UIApplication,其在应用程序的整个生命周期中只会创建一个实例,如果在编译过程中进行新的创建就会报错,如下:

UIApplication *app = [[UIApplication alloc]init];
//或者UIApplication *app = [[UIApplication new];

在这里插入图片描述
“There can only be one UIApplication instance”:该应用程序中只能有一个UIApplication实例。

单例模式的特点及使用情景

单例模式的关键特点:

  • 唯一性:单例类在应用程序的整个生命周期中只会创建一个实例(例如UIApplication)。
  • 全局访问点:单例类提供了一个全局的访问点,使得这个唯一实例可以被整个应用程序访问(例如:[UIApplication sharedApplication];)。
  • 线程安全:在多线程环境中,单例模式的实现需要确保实例的创建是线程安全的,以防止创建多个实例。
  • 延迟初始化:单例实例通常在第一次被引用时才创建,这样可以延迟初始化的开销,提高系统启动速度。

常见的适合使用单例模式的情况:

  1. 当你需要在整个程序的运行周期中,让一个类始终保持同一个实例。则必须使用单例模式;(例如 [UIApplication sharedApplication])
  2. 在生命周期中管理数据,例如自定义的管理中心或者[NSUserDefaults standardUserDefaults];
  3. 为了节省内存,部分类可以使用单例模式,例如多处使用的图片等。

单例模式的使用

单例模式的实现步骤:

1.私有化初始化方法:将初始化方法设为私有,以防止外部通过 new、alloc 或其他方式创建类的实例。

// 私有化初始化方法
- (instancetype)init {
    if ((self = [super init])) {
        // 执行初始化操作
    }
    return self;
}

// 使init方法不可用
+ (instancetype)new {
    return [SingleView sharedSingleView];
}

2.提供一个公共的类方法:提供一个公共的类方法,通常命名为 shared+类名,用于返回类的唯一实例。

//公共的类方法
+ (SingleView *)sharedSingleView {
    //声明一个SingleView类型的静态变量single,初始值为nil。静态变量的作用域限定在方法内部,但它的生命周期是整个应用程序,这意味着它只会被初始化一次。
    static SingleView *single = nil;
    
    //声明了一个dispatch_once_t类型的静态变量onceToken。dispatch_once是一个宏,用于确保代码块只执行一次。onceToken用于跟踪代码块是否已经执行过
    static dispatch_once_t onceToken;
    
    //执行dispatch_once宏,传入onceToken变量的地址和要执行的代码块。如果onceToken还没有被标记为已执行,代码块将被执行一次,并将onceToken标记为已执行,这样代码块就不会再次执行。
    dispatch_once(&onceToken, ^{
        //创建SingleView类的一个新实例,并将其赋值给single变量。super关键字表示调用父类的alloc方法,这里是NSObject类的方法。
        single = [[super alloc] init]; //等价于 single = [super new];
    });
    return single;
}

//重写allocWithZone:方法以确保当使用alloc或new创建对象时,总是返回单例对象。
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [SingleView sharedSingleView];
}

3.使用静态实例变量:存储类的唯一实例。

static SingleView *single = nil;

4.使用 dispatch_once:使用 dispatch_once 来确保实例化代码只执行一次,这保证了线程安全和单例的唯一性。

dispatch_once(&onceToken, ^{
        //创建SingleView类的一个新实例,并将其赋值给single变量。super关键字表示调用父类的alloc方法,这里是NSObject类的方法。
        single = [[super alloc] init]; //等价于 single = [super new];
    });

完整代码

//  SingleView.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SingleView : NSObject<NSCopying>

+ (SingleView *)sharedSingleView;

@end

NS_ASSUME_NONNULL_END
//  SingleView.m

#import "SingleView.h"

@implementation SingleView

// 私有化初始化方法
- (instancetype)init {
    if ((self = [super init])) {
        // 执行初始化操作
    }
    return self;
}

// 使init方法不可用
+ (instancetype)new {
    return [SingleView sharedSingleView];
}

//公共的类方法
+ (SingleView *)sharedSingleView {
    //声明一个SingleView类型的静态变量single,初始值为nil。静态变量的作用域限定在方法内部,但它的生命周期是整个应用程序,这意味着它只会被初始化一次。
    static SingleView *single = nil;
    
    //声明了一个dispatch_once_t类型的静态变量onceToken。dispatch_once是一个宏,用于确保代码块只执行一次。onceToken用于跟踪代码块是否已经执行过
    static dispatch_once_t onceToken;
    
    //执行dispatch_once宏,传入onceToken变量的地址和要执行的代码块。如果onceToken还没有被标记为已执行,代码块将被执行一次,并将onceToken标记为已执行,这样代码块就不会再次执行。
    dispatch_once(&onceToken, ^{
        //创建SingleView类的一个新实例,并将其赋值给single变量。super关键字表示调用父类的alloc方法,这里是NSObject类的方法。
        single = [[super alloc] init]; //等价于 single = [super new];
    });
    return single;
}

//重写allocWithZone:方法以确保当使用alloc或new创建对象时,总是返回单例对象。
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [SingleView sharedSingleView];
}

//重写copyWithZone:方法以确保当尝试复制单例对象时,总是返回单例对象本身。
+ (id)copyWitnZone:(struct _NSZone *)zone {
    return [SingleView sharedSingleView];
}

//重写mutableCopyWithZone:方法以确保当尝试创建可变副本时,总是返回单例对象本身。
+ (id)mutableCopyWithZone:(struct _NSZone *)zone {
    return [SingleView sharedSingleView];
}

//重写copyWithZone:方法以确保当尝试复制单例对象时,总是返回单例对象本身。
- (id)copyWithZone:(NSZone *)zone{
    return  [SingleView sharedSingleView];
}

//重写mutableCopyWithZone:方法以确保当尝试创建可变副本时,总是返回单例对象本身。
- (id)mutableCopyWithZone:(NSZone *)zone{
    return [SingleView sharedSingleView];
}

@end

总结

总的来说,单例模式是一种常用的软件开发模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。使用单例模式时要注意:
1.确保线程安全:单例的创建应该在多线程环境中是安全的。==使用 dispatch_once ==可以确保实例化代码只执行一次,从而避免多线程问题。
2.私有化构造函数:将类的构造函数标记为私有,以防止外部通过构造函数创建类的实例。
3.提供一个公共的获取实例的方法:提供一个公共的类方法,如 shared+类名。用于获取类的唯一实例。
4.管理资源和内存:单例对象通常在整个应用程序的生命周期内都存在,因此需要小心管理它所持有的资源,确保没有内存泄漏。
5.防止滥用单例模式:单例模式不适用于所有场景。它适用于那些确实只需要一个实例的类,如配置管理器、日志记录器等。滥用单例模式会增加系统的耦合度。
6.考虑使用协议和委托:如果单例需要与其他对象交互,考虑使用协议和委托而不是直接引用,以减少耦合。

参考文档:iOS 设计模式之单例模式
     ios 单例重新初始化方法


http://www.kler.cn/news/304999.html

相关文章:

  • 使用 PyTorch 构建 MNIST 手写数字识别模型
  • 基于单片机的水情监测站设计
  • TDengine 与飞腾腾锐 D2000 完成兼容互认证,推动国产软硬件深度融合
  • 【方法】如何禁止PDF转换成其他格式文件?
  • Dfa还原某app白盒aes秘钥
  • 微信小程序读写NFC标签(实现NFC标签快速拉起小程序)实战
  • 项目:构建高可用、负载均衡的高效Web服务器
  • 「Qt Widget中文示例指南」如何实现一个系统托盘图标?(二)
  • AndroidManifest.xml文件的重要信息
  • 【YashanDB知识库】archivelog磁盘满导致数据库abnormal
  • 哈莫尼斯 手工王国 Harmonis the hand made kingdoms,官方中文,解压即玩,
  • Java【泛型】
  • Oracle实现行转换成列
  • 【用Java学习数据结构系列】用堆实现优先级队列
  • R 绘图 - 饼图
  • 2024_中秋国庆双节来临 祝CSDN所有开发者与网站节日快乐
  • python画图|极坐标下的3D surface
  • 全局代理与智能分流:哪个更适合你?
  • Docker绑定端口后仍无法远程直接访问
  • react-intl——react国际化使用方案
  • 基于SpringBoot+Vue的高考志愿智能推荐系统
  • 怎么优化服务器的软件配置?
  • 【Lua学习】Lua入门
  • vue3+ts+supermap icilent3d for cesium功能集合
  • linux + 宝塔 + django + websocket 部署
  • C++:opencv获取矩阵中的最大最小值--cv::minMaxLoc
  • R语言进行无序多分类Logistic回归
  • 五星级可视化页面(24):管线管路流程图可视化大屏。
  • 文档智能:OCR+Rocketqa+layoutxlm
  • Maven下载安装