【iOS】单例模式

文章目录

  • 前言
  • 一、单例模式简介
  • 二、单例模式优缺点
    • 优点
    • 缺点
  • 三、模式介绍
    • 1.懒汉模式
    • 2. 饿汉模式
  • 总结


前言

在最初进行OC的学习时笔者了解过单例模式的基本使用,现撰写博客加深对单例模式的理解


一、单例模式简介

单例模式是一种常见的设计模式,其主要目的是确保一个类只有一个实例,并提供全局访问点。这样就大大节省了我们的内存,防止一个实例被重复创建从而占用内存空间。这种模式在需要一个共享资源或对象的情况下非常有用,但也有一些优点和缺点。

面向对象应用程序中的单例类(singleton class)总是返回自己的同一个实例。它提供了对象所提供的资源的全局访问点。与这类设计相关的设计模式称为单例模式。
大家在开发过程中也见过不少的单例,比如UIApplication、UIAccelerometer(重力加速)、NSUserDefaults、NSNotificationCenter,当然,这些是开发Cocoa Touch框架中的,在Cocoa框架中还有NSFileManager、NSBundle等。

二、单例模式优缺点

优点

  • 一个类只被实例化一次,提供了对唯一实例的受控访问
  • 节省系统资源
  • 允许可变数目的实例

缺点

  • 全局状态:单例模式可能导致全局状态的存在,这使得程序更难调试和理解。全局状态的改变可能会影响多个部分,增加了代码的复杂性。
  • 难以扩展:由于单例模式的实例是固定的,因此很难扩展以支持多个实例。如果需要多个实例,必须修改代码,将单例模式改为允许多个实例。
  • 隐藏依赖关系:使用单例模式的代码可能会隐藏对单例类的依赖关系,这使得代码更加耦合。这可能使单元测试和模块化难以实现。
  • 不适用于多线程环境:在多线程环境下,需要特殊的处理来确保单例模式的线程安全性。否则,可能会出现多个实例被创建的情况。

三、模式介绍

1.懒汉模式

懒汉模式(Lazy Initialization)是一种常见的单例设计模式,其主要特点是在需要时才会创建单例对象的实例,而不是在程序启动时就立即创建。懒汉模式通过延迟对象的初始化来节省资源和提高性能

举个简单的例子,你现在有衣服要洗,但是可以选择先不洗,等没衣服穿的时候再洗,这就是懒汉模式的逻辑——==需要用到实例时再去创建实例。


我们给出懒汉模式的代码:

ViewController.h

#import <UIKit/UIKit.h>@interface ViewController : UIViewController<NSCopying, NSMutableCopying>
+ (instancetype)shareSingleton;@end

ViewController.m

#import "ViewController.h"@interface ViewController ()@end@implementation ViewControllerstatic id _instance;+ (instancetype)allocWithZone:(struct _NSZone *)zone {if (_instance == nil) {//互斥锁防止被频繁加锁@synchronized (self) {if (_instance == nil) {//防止单例被多次创建_instance = [super allocWithZone:zone];}}}return _instance;
}+ (instancetype)shareSingleton {if (_instance == nil) { //防止被频繁枷锁@synchronized (self) {if (_instance == nil) {_instance = [[self alloc] init];}}}return _instance;
}- (void)viewDidLoad {[super viewDidLoad];_instance = [[NSString alloc] init];_instance = @"111";NSLog(@"%@", _instance);
}- (nonnull id)copyWithZone:(nullable NSZone *)zone {return _instance;
}- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {return _instance;
}
//copyWithZone: 和 mutableCopyWithZone: 方法是用于复制对象的方法。在这里,它们都被重写为返回单例对象的引用 _instance,以确保复制操作也得到同一个单例对象的引用,而不会创建新的对象副本。@end

使用懒汉模式时我们有几个问题值得我们讨论:

  1. 这样创建单例是否可以?
+ (instancetype)allocWithZone:(struct _NSZone *)zone {if (_instance == nil) {//互斥锁防止被频繁加锁@synchronized (self) {_instance = [super allocWithZone:zone];}}return _instance;
}

答案是不行的,因为我们只是锁住了对象的创建,如果两个线程同时进入if,那么就会产生两个对象

  1. 为什么要用static修饰单例?

如果我们不使用static,其他类中可以使用extern来拿到这个单例

extern id instance;
instance = nil;

如果在其他类中对单例进行如下操作,那么单例就会被重新创建,我们原本的单例对象中的内容就被销毁了。

具体用法可以参考这篇博客:【iOS】浅析static,const,extern关键字

  1. allocWithZone 与copyWithZone方法

通过代码可以看到我们的allocWithZone与shareSingleton方法是相同的,我们既可以通过shareSingleton创建单例,也可以通过allocWithZone创建单例。

copyWithZone: 和 mutableCopyWithZone: 方法是用于复制对象的方法。在这里,它们都被重写为返回单例对象的引用 _instance,以确保复制操作也得到同一个单例对象的引用,而不会创建新的对象副本。

2. 饿汉模式

在没有使用代码去创建对象之前,这个对象已经加载好了,并且分配了内存空间,当你去使用代码创建的时候,实际上只是将这个原本创建好的对象拿出来而已。

通俗的理解就是我们可以选择一回家就吃饭,也可以选择回家后躺一会再吃,躺一会再吃就是懒汉模式,直接吃就是饿汉模式

在我们的类加载过程中我们的单例就已经被创建了,我们无需在后面再去创建,直接使用即可

这里给出代码示例:

ehanViewController.h

#import <UIKit/UIKit.h>NS_ASSUME_NONNULL_BEGIN@interface ehanViewController : UIViewController<NSMutableCopying, NSCopying>//获取单例
+ (instancetype)sharedSingleton;@endNS_ASSUME_NONNULL_END

ehanViewController.m

#import "ehanViewController.h"@interface ehanViewController ()@end@implementation ehanViewControllerstatic id _instance;//当类加载到OC运行时环境中(内存),就会调用一次(一个类之后加载一次)
+ (void)load {_instance = [[self alloc] init];
}+ (instancetype)allocWithZone:(struct _NSZone *)zone {if (_instance == nil) {  //防止创建多次_instance = [super allocWithZone:zone];}return _instance;
}+(instancetype)sharedSingleton {return _instance;
}- (void)viewDidLoad {[super viewDidLoad];_instance = @"111";NSLog(@"%@", _instance);
}- (nonnull id)copyWithZone:(nullable NSZone *)zone {return _instance;
}- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone {return _instance;
}@end

总结

懒汉模式:

  • 优点:
    延迟加载:懒汉模式只有在第一次访问单例实例时才会进行初始化,可以节省资源,提高性能,因为实例只有在需要时才会被创建。
    节省内存:如果单例对象很大或者初始化过程开销较大,懒汉模式可以避免在程序启动时就创建不必要的对象。
    线程安全性:可以通过加锁机制(如双重检查锁定)来实现线程安全。
    缺点:
    线程安全性开销:懒汉模式在实现线程安全时可能需要额外的同步机制,这会引入一些性能开销。
    复杂性增加:实现线程安全的懒汉模式可能需要编写复杂的代码,容易引入错误。
  • 缺点:
    线程安全性开销:懒汉模式在实现线程安全时可能需要额外的同步机制,这会引入一些性能开销。
    复杂性增加:实现线程安全的懒汉模式可能需要编写复杂的代码,容易引入错误。

饿汉模式:

  • 优点:
    简单:饿汉模式实现简单,不需要考虑线程安全问题,因为实例在类加载时就已经创建。
    线程安全性:由于实例在类加载时创建,不会存在多个实例的风险,因此线程安全。
  • 缺点:
    无法实现延迟加载:饿汉模式在程序启动时就创建实例,无法实现延迟加载,可能会浪费资源,特别是当实例很大或初始化开销较大时。
    可能引起性能问题:如果单例类的实例在程序启动时没有被使用,那么创建实例的开销可能是不必要的。
    不适用于某些情况:如果单例对象的创建依赖于某些外部因素,而这些因素在程序启动时无法确定,那么饿汉模式可能不适用。

总的来说,懒汉模式适用于需要延迟加载实例的情况,可以节省资源和提高性能,但需要考虑线程安全性。饿汉模式适用于需要简单实现和线程安全性的情况,但不支持延迟加载。选择哪种模式应根据具体需求和性能考虑来决定。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/82497.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于HOG特征提取和GRNN神经网络的人脸表情识别算法matlab仿真,测试使用JAFFE表情数据库

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 1.HOG特征提取 2.GRNN神经网络 3.JAFFE表情数据库 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 .....................................…

Vue3 菜鸟入门(二)超详细:基本框架 模板语法和指令

【学习笔记】Vue3 菜鸟入门&#xff08;二&#xff09;超详细&#xff1a;基本框架 模板语法和指令 关键词&#xff1a;Vue 、Vue 3、Java、Spring Boot、Idea、数据库、一对一、培训、教学本文主要内容含Vue 基本框架 模板语法、指令计划1小时完成&#xff0c;请同学尽量提前…

nginx入门

概述/简介 Nginx 是一款轻量级的 Web 服务器/反向代理服务器及电子邮件代理服务器&#xff0c;在 BSD-like 协议下发行,具有高性能、高可靠性、丰富的模块化支持和简单易用的优势。 应用场景 动静分离: 为了加快网站的解析速度&#xff0c;我们可以把动态页面和静态页面分散到…

cutree 算法

传播 ​ 由于块与块之间具有参考关系&#xff0c;提升被参考块的质量&#xff0c;可以改善后续参考块的质量 ​ Pn1帧中CU0,1完全参考Pn的CU1,1。且Pn1帧中CU0,1块帧内预测和帧间预测的代价分别为 c x , y n 1 ( 0 , 0 ) c_{x,y}^{n1}(0,0) cx,yn1​(0,0)和 c x , y n 1 ( d…

2023Node.js零基础教程(小白友好型),nodejs新手到高手,(一)NodeJS入门

写在开始前 在无尽的代码汪洪中&#xff0c;闪耀着一抹绚丽的光芒。它叫做Web前端开发&#xff01; HTML是我们的魔法笔&#xff0c;是创造力的源泉。它将我们的思绪化为标签&#xff0c;将我们的想象变为元素。 在无尽的标签组合中&#xff0c;我们创造出独特的网页&#xff…

Webserver项目解析

一.webserver的组成部分 Buffer类 用于存储需要读写的数据 Channel类 存储文件描述符和相应的事件&#xff0c;当发生事件时&#xff0c;调用对应的回调函数 ChannelMap类 Channel数组&#xff0c;用于保存一系列的Channel Dispatcher 监听器&#xff0c;可以设置为epo…

【张兔兔送书第一期:考研必备书单】

考研书单必备 《数据结构与算法分析》《计算机网络&#xff1a;自顶向下方法》《现代操作系统》《深入理解计算机系统》《概率论基础教程&#xff08;原书第10版》《线性代数&#xff08;原书第10版&#xff09;》《线性代数及其应用》赠书活动 八九月的朋友圈刮起了一股晒通知…

【架构篇】Supabase架构和功能介绍

Supabase是什么 Supabase将自己定位为Firebase的开源替代品&#xff0c;提供了一套工具来帮助开发者构建web或移动应用程序。Supabase是建立在Postgres之上的&#xff0c;Postgres是一个免费的开源数据库&#xff0c;被认为是世界上最稳定、最先进的数据库之一。Supabase对标F…

C++DAY10 结构体·结构体指针

结构体指针的作用&#xff1a; 通过指针访问结构体中的成员。 *利用操作符->可以通过结构体指针访问结构体属性。 #include<iostream> using namespace std; //1、创建结构体 struct student {string name;int age;int FS; };int main() {//2、创建结构体变量struc…

《Envoy 代理:云原生时代的流量管理》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f6e0;️ 全栈技术 Full Stack: &#x1f4da…

C# Onnx Yolov8 Detect Poker 扑克牌识别

效果 效果一般&#xff0c;可下载数据集自己训练 Demo下载 数据集下载

SaaS架构C/S检验科LIS系统源码: 检验申请、标本编号、联机采集

适用于医院检验科实际需要的LIS管理系统, 实现检验业务全流程的计算机管理。从检验申请、标本编号、联机采集、中文报告单的生成与打印、质控图的绘制和数据的检索与备份。通过将所有仪器自身提供的端口与科室LIS系统中的工作站点连接,实现与医院HIS系统的对接。 通过门诊医生和…

docker-compose使用

docker-compose docker的项目编排 一、安装docker-compose Rocky Linux Rocky Linux安装Docker Compose的步骤如下&#xff1a; 安装Docker。您可以使用以下命令安装Docker&#xff1a; sudo dnf install docker-ce docker-ce-cli containerd.io安装Docker Compose。您可以…

java项目之抗疫医疗用品销售平台ssm+jsp

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的抗疫医疗用品销售平台。技术交流和部署相关看文章末尾&#xff01; 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java 框…

今天的消费情况

1、今天消费1710元 意外险 住院--集中参保 校---******----服 1220 rmB lunch 240Rmb

腾讯mini项目-【指标监控服务重构】2023-07-30

今日已办 调研 CPU & Memory Cadivisor &#xff23;adivisor -> Prometheus -> (Grafana / SigNoz Web) google/cadvisor: Analyzes resource usage and performance characteristics of running containers. (github.com) services:cadvisor:image: gcr.io/ca…

linux 磁盘命令之du和df命令

du相关的命令: du -ah 显示所有目录或文件所占空间 du -KG 显示所有目录或文件所占空间 块大小K为单位 du -BM 显示所有目录或文件所占空间 块大小M为单位 du -BG 显示所有目录或文件所占空间 块大小G为单位du -sh [目录名] 返回该目录的大小 du -sm [文件夹] 返回该文…

Jtti:nodejs怎么更新MySQL数据库

要更新MySQL数据库&#xff0c;您可以使用Node.js中的mysql模块。以下是一个简单的示例代码&#xff0c;用于更新数据库中的数据&#xff1a; javascript const mysql require(mysql); // 创建连接 const connection mysql.createConnection({ host: localhost, user: your_m…

短信、邮箱验证码本地可以,部署到服务器接口却不能使用

应对公司双验证要求&#xff0c;对本系统做邮箱、短信验证码登录&#xff0c;本地开发正常发送&#xff0c;到服务器上部署却使用失败&#xff0c;已全部解决&#xff0c;记录坑。 一、nginx拦截 先打开你的服务器 nginx.conf 看看有没有做接口拦截。&#xff08;本地可能做Sp…

爬虫逆向实战(32)-某号店登录(RSA、补环境、混淆)

一、数据接口分析 主页地址&#xff1a;某号店 1、抓包 通过抓包可以发现登录接口是/publicPassport/login.do 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现&#xff0c;有三个加密参数&#xff1a;username、password、captchaTok…