【OC】单例模式

文章目录

  • 前言
  • 概念
  • 优缺点
    • 优点
    • 缺点
  • 两种使用模式
    • 懒汉模式
      • 实现代码
      • 运行结果
    • 饿汉模式
      • 实现代码
      • 运行结果
  • 在自定义类方法时的几种常见写法
  • 总结

前言

在之前我们已经学习过单例模式的有关内容,但是只是最简单的单例,无法胜任多线程或者稍微多一点的情况便无法确定单例的唯一性,于是更深度的学习了单例模式

概念

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

即他用自己内部方法进行创立的唯一对象实例,并且可以被全局访问

优缺点

优点

  1. 全局访问

    单例模式就像一个全局变量,可以通过统一的入口来获取,并可以更方便的共享一些全局的数据与资源

  2. 节省资源

    只创建一次实例,避免了频繁的new/alloc

  3. 控制实例化过程

    通过私有函数和静态方法控制对象的唯一性,保持了数据的唯一性

缺点

  1. 隐藏依赖,增加耦合

    很多地方都直接访问单例,形成一种“隐形依赖”,在更改或替换单例时导致牵一发而动全身

  2. 不利于扩展与测试

    通常通过静态方法提供实例,全局固定,难以继承或替换

  3. 多线程安全问题

    在并发环境下,如果单例初始化没有处理好线程安全(比如加锁或使用 dispatch_once),可能会创建出多个实例,违背单例的初衷,尤其在懒汉式单例实现中,这一点必须特别小心。

两种使用模式

一般来说,创建一个单例之后要保证唯一实例的话要分别改写四种方法,即:用alloc init创建;通过类方法创建;通过copy创建;通过mutableCopy创建

而在改写这四种方法时按照创建时间主要分为两种,即懒汉模式和饿汉模式

懒汉模式

即在我们需要用到这个单例的时候,我们才开始创建这个唯一的实例,通过延迟对象的初始化来节省资源和提高性能,这种也是比较常用的创建单例模式的方式:

实现代码

+ (instancetype)sharedInstance {static Singletion *instance = nil;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 self;
}
- (id)mutableCopyWithZone:(NSZone *)zone {return self;
}
#import <Foundation/Foundation.h>
#import "Singletion.h"int main(int argc, const char * argv[]) {@autoreleasepool {Singletion *s1 = [Singletion sharedInstance];Singletion *s2 = [Singletion sharedInstance];Singletion *s3 = [s1 copy];Singletion *s4 = [s1 mutableCopy];NSLog(@"%d", s1 == s2);NSLog(@"%d", s1 == s3);NSLog(@"%d", s2 == s3);NSLog(@"%d", s1 == s4);}return 0;
}

这里涉及到了一个新的东西,即dispatch_once,经学长博客学习,发现其主要是按照onceToken的值来进行代码执行的

  1. onceToken = 0时,线程执行里面block中的代码
  2. onceToken = -1时,线程跳过block里的代码不执行
  3. onceToken = 其他值时,线程即会被阻塞,等待onceToken的值改变

当线程调用mySingleton方法时,此时 onceToken = 0,调用 block 中的代码,此时 onceToken =其他值。
当其他线程再调用 mySingleton 方法时,onceToken为其他值,线程阻塞。当 block 线程执行完 block之后,onceToken = -1,其他线程不再阻塞,跳过 block。下次再调用这个初始化方法时, block 已经为-1,直接跳过 block

运行结果

请添加图片描述

饿汉模式

饿汉模式指的是我们在一开始加载时就直接创建这个单例对象的实例,使用时再把这个对象拿出来,用到的这种方式不是特别常用,因为性能不如上面的懒汉模式

饿汉有个优点就是,因为这个实例在加载时就已经创建完成,所以其不存在多线程创建的问题,因而一般来说也不需要用dispatch_once或者加锁方法,当然用了也行,不过好像是有点多余的写法

实现代码

#import "Singletion.h"@implementation Singletionstatic Singletion* instance = nil;+ (void)load {instance = [[super allocWithZone: NULL] init];//NSLog(@"Singleton");
}
+ (instancetype)sharedInstance {return instance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {if (!instance) {instance = [super allocWithZone: zone];}return instance;
}
- (id)copyWithZone:(NSZone *)zone {return self;
}
- (id)mutableCopyWithZone:(NSZone *)zone {return self;
}
@end
int main(int argc, const char * argv[]) {@autoreleasepool {Singletion *s1 = [Singletion sharedInstance];Singletion *s2 = [Singletion sharedInstance];Singletion *s3 = [s1 copy];Singletion *s4 = [s1 mutableCopy];NSLog(@"%d", s1 == s2);NSLog(@"%d", s1 == s3);NSLog(@"%d", s2 == s3);NSLog(@"%d", s1 == s4);}return 0;
}

运行结果

请添加图片描述

在自定义类方法时的几种常见写法

首先我们知道饿汉一般是不需要担心其线程安全问题的,所以一般只考虑懒汉模式的几种写法,主要有两种

在懒汉模式中一般有两种写法,分别是GCD和加锁的写法,GCD的写法是现在写法更推荐的,因为其性能极快且第一次使用后后续基本无开销,而使用加互斥锁@synchronized的方式性能较慢,且每次使用时都有锁的开销所以不常用

GCD的写法在上面已经给出,下面我给出使用加锁方式的代码:

static Singletion* instance = nil;
+ (id)sharedInstance {if (instance == nil) {@synchronized (self) {if (instance == nil) {instance = [[super allocWithZone: NULL] init];}}}return instance;
}
+ (id)allocWithZone:(struct _NSZone *)zone {if (instance == nil) {@synchronized (self) {if (!instance) {instance = [[super allocWithZone: NULL] init];}}}return instance;
}
- (id)copyWithZone:(NSZone *)zone {return self;
}
- (id)mutableCopyWithZone:(NSZone *)zone {return self;
}

总结

总而言之,懒汉模式一般用于需要延迟加载实例的情况,可以节省资源,提高性能,但是需要考虑线程安全的问题;饿汉模式适用于需要简单实现和线程安全的情况,但是不支持延迟加载,在程序开始时便加载完成了

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

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

相关文章

机器学习(七)决策树-分类

一 概念1 决策节点通过条件判断而进行分支选择的节点。将样本的属性值&#xff0c;也就是特征值与决策节点上的值进行比较&#xff0c;从而判断它的流向。2 叶子节点没有子节点的节点&#xff0c;表示最终的决策结果。3 决策树的深度所有节点的最大层次数决策树具有一定的层次结…

IT 服务管理的新格局:从工单系统到一体化 ITSM 平台

企业 IT 部门的角色转变在过去&#xff0c;IT 部门更多被视为“技术支持”&#xff0c;主要负责设备维护和故障处理。但随着数字化转型加速&#xff0c;IT 已经成为业务连续性和创新的重要推动力。从客户体验到数据安全&#xff0c;从业务敏捷到成本控制&#xff0c;IT 服务管理…

创建一个Spring Boot Starter风格的Basic认证SDK

文章目录前言设计思路SDK实现步骤1. 创建SDK Maven项目&#xff08;sdk目录&#xff09;2. 实现配置类3. 实现认证逻辑4. 实现拦截器5. 实现自动配置6. 创建spring.factories文件使用方集成步骤1. 引入SDK依赖2. 配置Application属性3. 创建测试接口4. 测试接口访问SDK扩展功能…

mybatis处理统计sql进度丢失问题

如何处理统计sql进度丢失 SELECT sum(decimal_column) AS sum_value FROM your_table如上sql执行时没有问题&#xff0c;在数据库可视工具可以正常显示&#xff0c;但是在mybatis执行时&#xff0c;却出现解决办法 使用转 decimal 控制精度 SELECT CAST(SUM(decimal_column) A…

全球首款!科聪控制器获德国 TÜV 莱茵功能安全认证

近日&#xff0c;浙江科聪控制技术有限公司&#xff08;以下简称"科聪"&#xff09;的安全移动机器人控制器MSC5000荣获全球权威认证机构德国莱茵TV集团&#xff08;TV Rheinland&#xff09;颁发的功能安全认证证书。这款控制器是全球首款通过SIL3、PLe 认证的移动机…

pureadmin的动态路由和静态路由

在 PureAdmin&#xff08;基于 Vue3 的后台管理框架&#xff09;中&#xff0c;静态路由和动态路由是实现路由管理的两种方式&#xff0c;主要区别在于路由的定义时机、加载方式和灵活性&#xff0c;具体区别如下&#xff1a; 1. 静态路由 定义方式&#xff1a;路由规则在代码中…

第3章:CPU实战

1. Linux操作系统CPU平均负载 以前我们总认为CPU使用率和CPU平均负载是一样的&#xff0c;负载高了就是CPU使用率提高。但是到底是什么情况呢&#xff1f; 1.1. CPU的平均负载 单位时间内 系统处于 可运行状态 和不可中断状态 的平均进程数&#xff0c;就是平均活跃进程数&a…

【Vue3】06-利用setup编写vue(1)

其它篇章&#xff1a; 1.【Vue3】01-创建Vue3工程 2.【Vue3】02-Vue3工程目录分析 3.【Vue3】03-编写app组件——src 4.【Vue3】04-编写vue实现一个简单效果 5.【Vue3】05-Options API和Composition API的区别 6.【Vue3】06-利用setup编写vue&#xff08;1&#xff09; 7.【Vue…

UDS NRC速查

目录 NRC 一、通用NRC(0x10~0x5F) 二、数据相关NRC(0x70~0x8F) 三、会话与状态NRC 注意事项 UDS中的NRC(Negative Response Code)即否定响应码,用于在诊断通信中表示服务端无法成功执行客户端请求的原因。以下是一些常用的UDS NRC码及其含义: HEX Name Description 01 …

【AI论文】多模态大型语言模型的视觉表征对齐

摘要&#xff1a;通过视觉指令微调训练的多模态大型语言模型&#xff08;MLLMs&#xff09;在各类任务中均取得了优异表现&#xff0c;然而在以视觉为中心的任务&#xff08;如物体计数或空间推理&#xff09;中&#xff0c;其性能仍存在局限。我们将这一差距归因于当前主流的纯…

SKywalking Agent配置+Oracle监控插件安装指南

SKywalking Agent配置Oracle监控插件安装指南前言&#xff1a; SkyWalking Elasticsearch8 容器化部署指南 Skywalking版本&#xff1a;V10.2.0 Skywalking Agent版本&#xff1a;V9.4.0 Skywalking Agent下载地址&#xff1a;Downloads | Apache SkyWalking 插件下载地址&…

ES相关问题汇总

问题一&#xff1a;关于【QueryBuilder对象】和【Query String语法】查询时底层运行方式和结果的差异

5. STM32 时钟系统分配

文章目录下述将以stm32f407 为例1. 时钟系统及频率分析2. 时钟配置下述将以stm32f407 为例 1. 时钟系统及频率分析 上述STM32F4时钟系统图解析入下&#xff1a; STM32F407 系列微控制器&#xff08;基于 Cortex-M4 内核&#xff0c;带 FPU&#xff09;的工作频率配置如下&…

《从 0 建立测试开发认知:先搞懂 “是什么”,再学 “怎么做”》

&#x1f525;个人主页&#xff1a;草莓熊Lotso &#x1f3ac;作者简介&#xff1a;C研发方向学习者 &#x1f4d6;个人专栏&#xff1a; 《C知识分享》《Linux 入门到实践&#xff1a;零基础也能懂》《数据结构与算法》《测试开发实战指南》《算法题闯关指南》 ⭐️人生格言&a…

net::ERR_EMPTY_RESPONSE

net::ERR_EMPTY_RESPONSE表现解决表现 Java后端封装一个接口&#xff0c;透传前端参数&#xff0c;请求到其他模块服务 本地开发环境联调时是没有问题&#xff0c;测试环境上报错 1.前端报错&#xff0c;F12检查&#xff0c;network上的请求&#xff0c;返回response选项中为空…

在线多功能环境音生成器

https://oltool.cc/toolbox/huanjingyins.html 关于环境音生成器介绍&#xff1a; 1、本工具可以混合各种声音&#xff0c;比如下雨声&#xff0c;打雷声&#xff0c;海浪声&#xff0c;鸟叫以及虫鸣声等&#xff0c;生成新的环境声。 2、定时器&#xff1a;可以设置倒计时&…

本地电脑映射端口到外网访问的开启方法和注意事项,内网服务提供跨网使用简单操作实现

在计算机网络中&#xff0c;端口映射是一项重要的技术&#xff0c;它允许外网用户访问局域网内的特定设备或服务。当我们在本地电脑搭建部署项目应用后&#xff0c;就可以通过映射端口的方式&#xff0c;简单快速稳定的提供互联网访问服务。以下将详细介绍如何开启电脑映射端口…

Java 大视界 -- Java 大数据在智能医疗健康档案数据分析与个性化健康管理中的应用(410)

Java 大视界 -- Java 大数据在智能医疗健康档案数据分析与个性化健康管理中的应用&#xff08;410&#xff09;引言&#xff1a;正文&#xff1a;一、2023 年 6 月智能医疗健康档案的核心落地需求&#xff08;政策 业务双驱动&#xff09;1.1 政策倒逼的数据应用痛点&#xff…

微服务架构的基石:Nacos全方位解析与Java实战指南

引言在云原生与微服务浪潮席卷而来的今天&#xff0c;服务的治理与配置的管理变得前所未有的复杂。一个个单一的应用被拆分为数十甚至上百个微服务&#xff0c;如何让这些服务轻松地发现彼此&#xff1f;如何在不重启应用的情况下动态调整所有服务的参数&#xff1f;这些问题直…

IDA pro 生成idapro.hexlic

先安装IDA pro&#xff0c;安装好后&#xff0c;把根目录中的 ida32.dll和ida.dll赋值到python文件脚本同目录中&#xff0c;如图。 直接运行py import json import hashlib import os from datetime import datetime, timedelta import platform import winregname input(&…