【iOS】单例模式

目录

前言

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

单例模式

认识单例模式

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

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

Java中单例模式定义:"一个类有且仅有一个实例,并且自行实例化向整个系统提供。"

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

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

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

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

objectivec 复制代码
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 或其他方式创建类的实例。

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

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

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

objectivec 复制代码
//公共的类方法
+ (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.使用静态实例变量:存储类的唯一实例。

objectivec 复制代码
static SingleView *single = nil;

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

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

完整代码

objectivec 复制代码
//  SingleView.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SingleView : NSObject<NSCopying>

+ (SingleView *)sharedSingleView;

@end

NS_ASSUME_NONNULL_END
objectivec 复制代码
//  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 单例重新初始化方法

相关推荐
用户0915 小时前
SwiftUI Charts 函数绘图完全指南
ios·swiftui·swift
YungFan15 小时前
iOS26适配指南之UIColor
ios·swift
权咚1 天前
阿权的开发经验小集
git·ios·xcode
用户091 天前
TipKit与CloudKit同步完全指南
ios·swift
法的空间2 天前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
侃侃_天下2 天前
最终的信号类
开发语言·c++·算法
echoarts2 天前
Rayon Rust中的数据并行库入门教程
开发语言·其他·算法·rust
2501_915918412 天前
iOS 上架全流程指南 iOS 应用发布步骤、App Store 上架流程、uni-app 打包上传 ipa 与审核实战经验分享
android·ios·小程序·uni-app·cocoa·iphone·webview
Aomnitrix2 天前
知识管理新范式——cpolar+Wiki.js打造企业级分布式知识库
开发语言·javascript·分布式
每天回答3个问题2 天前
UE5C++编译遇到MSB3073
开发语言·c++·ue5