OC-单例模式

文章目录

单例模式

定义

单例模式,简单的说就是一个类始终只对应同一个对象,每次获取这个类的对象获得的都是同一个实例

如果一个类始终只能创建一个实例,那么这个类被称为单例类。单例类只有一个全局的接口来访问这个实例。当第一次载入的时候,他通常使用延迟加载的方创建唯一单例。在程序中一个单例只初始化一次,为了保证在使用中始终存在,单例类的存储是在存储器的全局区域,在编译时分配内存,只要程序在运行单例就始终存在,占用内存。在APP结束运行后释放这部分内存。但是在系统方法中,存在未知的自动释放池,如果对一个对象进行自动释放的话,可能进入未知的释放池,出现内存问题。即为单例模式不能自动释放的原因

特点

  1. 单例类是一个类,这个类创造出的对象是单例对象
  2. 单例对象使用类方法创建
  3. 单例一旦被创建出来,直到程序结束运行才会释放
  4. 单例不用我们来管理内存,内存会随着程序关闭而被释放

使用原因

节省内存,防止一个实例被重复创建从而占用内存空间。

缺点

  • 全局状态:可能导致全局状态的存在,使得程序难以调试,一个地方修改容易导致很多地方发生变化
  • 难以拓展:单例模式的实例是固定的,难以拓展以支持多个实例,必须修改代码,使单例类丢失单例的特性
  • 隐藏依赖关系:可能会隐藏单例类的依赖关系,代码更加耦合。

模式介绍

懒汉模式

是一种常见的单例设计模式,其主要特点是在需要时在创建单例对象的实现,通过延迟对象的初始化来节省资源和提高性能。适用于访问量较小的情况,使用时间来换取空间

同步锁实现
objectivec 复制代码
#import "Person.h"

@implementation Person
static id instance = nil;
+ (instancetype)sharedInstance {
    @synchronized (self) {
        if (!instance) {
            instance = [[super allocWithZone:NULL] init];
        }
    }
    return instance;
}
@end

这一段代码提供了一个全局访问点sharedInstace类方法提供给外部访问这个单例,在方法内部通过添加了一个同步锁,限制了同一时间只有一个线程访问临界区的代码。但是这里如果instance已经存在是没有必要进入锁的,所以可以再加个判断如下:

objectivec 复制代码
#import "Person.h"

@implementation Person
static id instance = nil;
+ (instancetype)sharedInstance {
    if (!instance) {
        @synchronized (self) {
            if (!instance) {
                instance = [[super allocWithZone:NULL] init];
            }
        }
    }
    return instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    if (!instance) {
        @synchronized (self) {
            if (!instance) {
                instance = [super allocWithZone:zone];
            }
        }
    }
    return instance;
}

- (id)copyWithZone:(NSZone *)zone {
    return self;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    return self;
}
@end

对于allocWithZone的参数,传什么其实都无所谓,分配的内存区域不会改变

内层if的作用:假设有两个线程A和B同时调用了sharedInstance,线程A先一步获取锁,进入代码块,此时线程B等待锁释放,当线程A初始化instance后释放锁,B获得锁,如果没有内层if判断,会再次创建实例,破坏了单例的唯一性

dispatch_once

通过一个静态的dispatch_once变量来跟踪代码的执行状态,第一次调用时原子操作发现标记状态为未执行代码块,并原子性的将标记设为已执行,后续监测到标记为已执行,就会跳过该代码块。非常高效、没有阻塞开销

objectivec 复制代码
#import "Person.h"

@implementation Person
static id instance = nil;
+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[super allocWithZone:NULL] init];
    });
    return instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [super allocWithZone:zone];
    });
    return instance;
}

- (id)copyWithZone:(NSZone *)zone {
    return self;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    return self;
}
@end

我们打印出不同情况下的对象地址如下:

饿汉模式

在类加载过程就完成这个单例的创建和初始化

实现
objectivec 复制代码
#import "Person.h"

@implementation Person
static id instance = nil;

+ (void)load {
    instance = [[super allocWithZone:NULL] init];
}

+ (instancetype)sharedInstance {
    return instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return instance;
}

- (instancetype)init {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"init一次");
    });
    return self;
}

- (id)copyWithZone:(NSZone *)zone {
    return self;
}

- (id)mutableCopyWithZone:(NSZone *)zone {
    return self;
}

@end

总结

懒汉模式

优点
  1. 延迟加载,节省资源,提高性能。
  2. 避免在程序启动时就创造不必要的对象,造成额外开销
  3. 可以通过加锁实现线程安全
缺点
  1. 为实现线程安全使用锁机制,可能会引起一些性能开销

饿汉模式

优点
  1. 实现简单,不需要考虑线程安全问题,实例在类加载时就已经创建了,所以不用考虑创建多个实例的风险
缺点
  1. 程序启动时就加载创建实例,可能会浪费资源,引起性能问题
  2. 如果单例对象的创建需要建立在某些外部前提下,那么不适合饿汉模式
相关推荐
fthux3 小时前
Tick Rest,一个休息提醒工具的自我修养
macos·开源·swift
FPGA小迷弟1 天前
FPGA 与千兆以太网:各类物理接口的形式、区别、使用方法与应用场景详解
tcp/ip·macos·fpga开发·udp·fpga
2501_916008892 天前
iOS App 图标、启动屏和多语言搭配 方法,上架前使用KXBuild一次做好 App 图标
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
2501_915918412 天前
iOS 推送通知怎么实现,从 APNs p8 密钥到 iOS 真机收到第一条推送
vscode·ios·objective-c·个人开发·swift·敏捷流程
周小董3 天前
[1379]mac安装nvm
macos
bossjuemfc3 天前
不记得文件名时,Mac 上的搜索还能怎么做?
macos
2501_915909063 天前
Windows 打开 Xcode 工程,编译调试 Xcode 项目并和 Mac 同事协作
ide·windows·vscode·macos·ios·个人开发·xcode
请为小H留灯4 天前
Mac 常用操作与维护技巧
macos·电脑·清理电脑·常用技巧
hantmac4 天前
不记得文件名时,Mac 上的搜索还能怎么做?
人工智能·macos
这是谁的博客?4 天前
AI 加速器 RTL 数字系统设计深度解析:从 MAC 阵列 Verilog 实现到时序收敛与时钟功耗的芯片落地全链路
人工智能·macos·ai·verilog·数字ic设计·ai芯片·rtl