iOS设计模式 ——单例模式详解以及严格单例模式注意点

一、我们常用的单例有哪些?

  1. [[UIApplication sharedApplication] statusBarStyle];//系统中的单例模式,通过它获取到状态栏的style

  1. [NSNotificationCenter defaultCenter] addObserver:<#(nonnull id)#> selector:<#(nonnull SEL)#> name:<#(nullable NSString *)#> object:<#(nullable id)#>];//defaultCenter从控制中心类中获取到了单例的实例
  1. [NSUserDefaults standardUserDefaults] setObject:<#(nullable id)#> forKey:<#(nonnull NSString *)#>];
  2. [NSFileManager defaultManager];

从这些常用的单例可以发现,通过这些常用的单例方法来获取到这个类的唯一实例,再在这个实例的基础上进行相关的操作、作业。

二、单例模式基本原理

单例模式,一般用来管理某些资源的,用来管理某个对象,他这个对象持有了某些核心资源,这个资源可以全局共享。大部分情况我们使用单例模式就是为了共享信息 ,一般作为管理中心。

缺点是因为他共享了信息,就破坏了设计模式中的最少知识原则,产生了耦合,破坏了封装性,。但是在解决问题的过程中,这种不好的地方也是可以忽略的。


下面我们来自己写一个单例的例子,详细的讲一下对单例的理解。创建一个UserInfoManagerCenter的类

仿照系统的单例形式自己写这个类方法。

  1. #import <Foundation/Foundation.h>
  2. @interface UserInfoManagerCenter : NSObject
  3. @property (nonatomic ,strong) NSString *name;
  4. @property (nonatomic ,strong) NSString *age;
  5. + (instancetype)managerCenter;
  6. @end

UserInfoManagerCenter.m中实现这个方法

  1. #import "UserInfoManagerCenter.h"
  2. @implementation UserInfoManagerCenter
  3. /**
  4. *  常规做法
  5. */
  6. +(instancetype)managerCenter
  7. {
  8.    static UserInfoManagerCenter *center = nil;//静态变量持有这个对象
  9.    if (center == nil) {
  10.        center = [[UserInfoManagerCenter alloc]init];
  11.    }
  12.    return center;
  13. }
  14. @end

但是这种方法并不好,当多个地方调用这个方法时,会造成同时都进入到alloc init。

因此,使用第二种方法

  1. #import "UserInfoManagerCenter.h"
  2. @implementation UserInfoManagerCenter
  3. /**
  4. *  第二种方案,用dispatch_once来解决竞争问题
  5. */
  6. +(instancetype)managerCenter
  7. {
  8.    static UserInfoManagerCenter *center = nil;
  9.    static dispatch_once_t onceToken;
  10.    dispatch_once(&onceToken, ^{
  11.        center = [[UserInfoManagerCenter alloc]init];
  12.    });
  13.    return center;
  14. }
  15. @end

当然还有第三种方法    ---   initialize的作用,同一个类初始化时只会调用一次。

  1. #import "UserInfoManagerCenter.h"
  2. static UserInfoManagerCenter *center = nil;
  3. @implementation UserInfoManagerCenter
  4. /**
  5. * 第三种方法,每个类调用任意方法时都会提前调用的这个initialize方法,initialize的作用,同一个类初始化时只会调用一次。所以说我们将单例写在这个地方也是没有问题的,但是不推荐
  6. */
  7. +(void)initialize
  8. {
  9. if (self == [UserInfoManagerCenter class]) {
  10. center = [[UserInfoManagerCenter alloc]init];
  11. }
  12. }
  13. +(instancetype)managerCenter
  14. {
  15. return center;
  16. }
  17. @end

让我们来验证下,然后在AppDelegate里赋值

  1. #import "AppDelegate.h"
  2. #import "UserInfoManagerCenter.h"
  3. @interface AppDelegate ()
  4. @end
  5. @implementation AppDelegate
  6. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  7. UserInfoManagerCenter *center = [UserInfoManagerCenter managerCenter];
  8. center.name = @"YUSIR";
  9. return YES;
  10. }

在ViewController的viewDidLoad里取出值查看结果

  1. #import "ViewController.h"
  2. #import "UserInfoManagerCenter.h"
  3. @interface ViewController ()
  4. @end
  5. @implementation ViewController
  6. - (void)viewDidLoad {
  7. [super viewDidLoad];
  8. UserInfoManagerCenter * center = [UserInfoManagerCenter managerCenter];
  9. NSLog(@"name:%@",center.name);
  10. }

三种方法结果能打印出来,单例实现了资源共享

三、严格单例模式的注意点

下面来简单谈谈严格的单例模式,有三个问题可能需要注意一下:

1.如何防止继承;

2.如何确保实例对象只出现一个;

3.防止实例对象被释放掉;

第一个问题,防止继承

  1. +(instancetype)managerCenter
  2. {
  3. static UserInfoManagerCenter *center = nil;
  4. static dispatch_once_t onceToken;
  5. dispatch_once(&onceToken, ^{
  6. center = [[UserInfoManagerCenter alloc]init];
  7. });
  8. //防止子类重载调用使用
  9. NSString *classString = NSStringFromClass([self class]);//获取当前类的名字
  10. if ([classString isEqualToString:@"UserInfoManagerCenter"] == NO) {
  11. NSParameterAssert(nil); //填nil会导致程序崩溃
  12. }
  13. return center;
  14. }

创建一个子类继承自UserInfoManagerCenter,调用managerCenter会直接崩溃,比较简单这里就不截图了

第二个问题,如何确保实例对象只出现一个。除了类方法之类还有init方法,只能重写他的init方法,来实现init方法失效

  1. static UserInfoManagerCenter *center = nil;
  2. @implementation UserInfoManagerCenter
  3. +(instancetype)managerCenter
  4. {
  5. static dispatch_once_t onceToken;
  6. dispatch_once(&onceToken, ^{
  7. center = (UserInfoManagerCenter *)@"UserInfoManagerCenter";
  8. center = [[UserInfoManagerCenter alloc]init];
  9. });
  10. //防止子类重载调用使用
  11. NSString *classString = NSStringFromClass([self class]);//获取当前类的名字
  12. if ([classString isEqualToString:@"UserInfoManagerCenter"] == NO) {
  13. NSParameterAssert(nil); //填nil会导致程序崩溃
  14. }
  15. return center;
  16. }
  17. - (instancetype)init {
  18. NSString *string = (NSString *)center;
  19. if ([string isKindOfClass:[NSString class]]== YES && [string isEqualToString:@"UserInfoManagerCenter"]) {
  20. self = [super init];
  21. if (self) {
  22. //防止子类重载调用使用
  23. NSString *classString = NSStringFromClass([self class]);//获取当前类的名字
  24. if ([classString isEqualToString:@"UserInfoManagerCenter"] == NO) {
  25. NSParameterAssert(nil); //填nil会导致程序崩溃
  26. }
  27. }
  28. return self;
  29. }else {
  30. return nil;
  31. }
  32. }

第三个,由于现在是项目是ARC开发的,是引用计数管理的。无法重载release,可以跳过这个问题。

当然严格的单例模式,只要注意避免类似情况发生,就可以不用过多考虑这些负担了。







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

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

相关文章

科学计算库学习报告

numpy与matplotlib的学习随笔 我爱代码 import numpy as npimport matplotlib.pyplot as pltimport matplotlibmatplotlib.rcParams[font.family]SimHeimatplotlib.rcParams[font.sans-serif][SimHei]labelsnp.array([第一次,第二次,第三次,第四次,第五次,第六次])nAttr6datanp…

前端网页 — 初始化文件

/*--------------------------初始化代码*/ /*清除默认的margin和padding*/ * {margin: 0;padding: 0; }/*清除小圆点*/ ul {list-style: none; }/*清除a标签默认的下划线*/ a {text-decoration: none; }/*表格边框合并*/ table {border-collapse: collapse; }/*去除input标签点…

数据库系统原理(第二章关系数据库 )

一、关系数据库概述 20世纪80年代后&#xff0c;在商用数据库管理系统中&#xff0c;&#xff08; 关系模型 &#xff09;逐渐取代早 期的网状模型和层次模型&#xff0c;成为主流数据模型 SQL3&#xff08;SQL-99&#xff09;:1999年 SQL2&#xff08;SQL-92&#xff09;&…

iOS NSMutableAttributedString常用方法总结

NSAttributedString 叫做富文本&#xff0c;是一种带有属性的字符串&#xff0c;通过它可以轻松的在一个字符串中表现出多种字体、字号、字体大小等各不相同的风格&#xff0c;还可以对段落进行格式化&#xff0c;一般都是对可变富文本&#xff08;NSMutableAttributedString&a…

微信小程序image bindload事件失效不触发

1.先上代码 <template><div :class"[img-wrapper, className]"><img :src"defaultSrc" :mode"mode" class"default-img" :hidden"loaded"><img :src"src" :mode"mode" load"…

数据可视化(BI报表的开发)第三天

20、销售统计-布局 html结构&#xff1a; <!-- 销售额 --><div class"sales panel"><div class"inner"><div class"caption"><h3>销售额统计</h3><a href"javascript:;" class"active&q…

软件开发工具(第1章:绪论)

一、 软件开发工具的由来 计算机语言和软件开发工具的发展和历史 机器语言&#xff08;第一代语言&#xff09;&#xff1a;难以记忆的、无意义的、二进 制的字符串 汇编语言&#xff08;第二代语言&#xff09;针对难以记忆的、无意义的、二进 制的字符串、人们试图用英语中具…

Swift傻傻分不清楚系列(一)常量与变量

菜鸟从零开始认识学习Swift。感谢大神们翻译的文档。搬到自己小黑屋里慢慢看~~~ 本页包含内容&#xff1a; 常量和变量声明常量和变量类型标注常量和变量的命名输出常量和变量注释分号 Swift 是一门开发 iOS, OS X 和 watchOS 应用的新语言。然而&#xff0c;如果你有 C 或者 …

Saiku Table展示数据合并bug修复(二十五)

Saiku Table展示数据合并bug修复 Saiku以table的形式展示数据&#xff0c;如果点击了 非空的字段 按钮&#xff0c;则会自动进行数据合并&#xff0c;为空的数据行以及数据列都会自动隐藏掉。 首先我们应该定位问题&#xff1a; 1.查看接口返回值&#xff0c;会发现接口返回都正…

软件开发工具(第2章:软件开发过程及其组织)

一、软件开发的困难 程序员做好软件工作的关键是什么&#xff1f; 关键是两个转换&#xff1a; 第一个转换是用户对软件功能的理解与程序员对软件功能的理解之间的转换。 &#xff08;不同⾏业的⼈员对于事物的认识⽅法与描述⽅法是不同的。&#xff09; 第二个转换要解决的是人…

数据可视化(BI报表的开发)第四天

练习题&#xff1a; 先找出字符串 ‘8587263747153203552943982’ 中出现次数最多的数字及次数&#xff0c;然后去重后并排序&#xff08;不准使用sort&#xff09;&#xff0c;使得到结果为 ‘0123456789’。 要求1&#xff1a;找到出现最多的数字和出现的次数 // 1、找出出…

Swift傻傻分不清楚系列(二)数据类型

本页包含内容&#xff1a; 整数整数范围IntUInt浮点数类型安全和类型推断数值型字面量数值型类型转换整数转换数整数和浮点数转换类型别名布尔值 整数 整数就是没有小数部分的数字&#xff0c;比如42和-23。整数可以是有符号&#xff08;正、负、零&#xff09;或者无符号&…

Python打卡第四周

这一周鸽了好久&#xff0c; 因为最近在准备比赛。课程一直没跟上。。。 今天整理完本周的知识之后休息一周复习之前的 好了。 上总结 第一天 装饰器定义函数bar&#xff0c;在foo中调用 # def foo(): # # print(in the foo) # # bar() # # foo()def bar():print(in th…

网络经济与企业管理(第 1 章:企业管理概论)

一、企业的概念 什么是企业&#xff1f; 1.企业以市场为导向&#xff0c;以价值增值作为经济活动的目的 2.企业是从事商品生产和流通的经济组织 3.企业经营过程中要自主经营、自负盈亏、独立核算和承担风险&#xff0c;具有法人资格的基本经济单位 企业发展的三个时期&#xff…

js高级 — ES6

ECMAScript 6 目标&#xff1a;学习完 ES6 可以掌握方便后续的开发&#xff0c;未来工作中大量使用 ES6 开发 ECMAScript 6 介绍ECMAScript 6 新增语法内置对象的扩展ECMAScript 6 降级处理&#xff08;学习完node再讲&#xff09; 1. ECMAScript 6 介绍 ES – ECMAScript …

Swift傻傻分不清楚系列(三)元组与可选类型

本页包含内容&#xff1a; 元组可选nilif 语句以及强制解析可选绑定隐式解析可选类型错误处理断言 元组 元组&#xff08;tuples&#xff09;把多个值组合成一个复合值。元组内的值可以是任意类型&#xff0c;并不要求是相同类型。 下面这个例子中&#xff0c;(404, "Not…

去死吧!USB转串口!!!

首先&#xff0c;这个题目有两种歧义&#xff1a;1、USB转232串口&#xff08;严格说就是这种&#xff09;&#xff01; 2、USB转USART串口&#xff08;通常都是这么叫&#xff0c;认为就是这&#xff0c;理论上是错误的&#xff0c;歧义所在&#xff09;&#xff01; USB转TTL…

IDEA微服务项目的application.yml没有绿色叶子的解决办法

1.今天在写微服务项目的时候成功入坑&#xff0c;那么问题是啥呢&#xff1f;接下来和我一起走入bug的世界吧&#xff0c;让我们看看究竟是怎么回事。 *问题描述    1.application.yml是灰色的小格子 2.实在难看 *需要解决的最终结果 1.有绿色的小叶子 解决方案上图 1. 2. …

Ajax — 第一天

上网的目的 本质目的&#xff1a;浏览和消费资源 资源&#xff1a;文字、图片、音频、视频…资源存在哪里&#xff1a;服务器上 服务器的概念 是负责存放和对外提供资源的电脑。它的性能比普通的计算机好太多了 客户端 获取和消费资源的电脑&#xff0c;叫做客户端。 我…

linux 查看进程

1.ps 各字段含义 如果让程序始终在后台执行&#xff0c;即使关闭当前的终端也执行&#xff08;之前的&做不到&#xff09;&#xff0c;这时候需要nohup。 该命令可以在你退出帐户/关闭终端之后继续运行相应的进程。关闭中断后&#xff0c;在另一个终端jobs已经无法看到后台…