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

  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,可以跳过这个问题。

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


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

  1. Java单例模式详解--七种单例模式实现+单例安全+实际应用场景

    单例模式 保证了一个类只有一个实例,并且提供了一个全局访问点.单例模式的主要作用是节省公共资源,方便控制,避免多个实例造成的问题. 实现单例模式的三点: 私有构造函数 私有静态变量维护对象实例 公有静 ...

  2. java connection 单例_Java设计模式之单例模式详解

    Java设计模式之单例模式详解 什么是设计模式 设计模式是在大量的实践中总结和理论之后优选的代码结构,编程风格,以及解决问题的思考方式.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可 ...

  3. C++设计模式--单例模式详解(懒汉模式、饿汉模式、双重锁)

    C++设计模式--单例模式详解(懒汉模式.饿汉模式.双重锁) 应用场景 一.单例模式是什么? 二.使用步骤 1.UML图 2.代码实现 应用场景 通常我们在做通讯的时候,我们跟服务器数据交互,假如每次 ...

  4. 单例模式(单例设计模式)详解

    在有些系统中,为了节省内存资源.保证数据内容的一致性,对某些类要求只能创建一个实例,这就是所谓的单例模式. 单例模式的定义与特点 单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自 ...

  5. 单例模式应用场景_三、单例模式详解

    4.单例模式详解 4.1.课程目标 1.掌握单例模式的应用场景. 2.掌握IDEA环境下的多线程调试方式. 3.掌握保证线程安全的单例模式策略. 4.掌握反射暴力攻击单例解决方案及原理分析. 5.序列 ...

  6. 以下属于单例模式的优点的是_三、单例模式详解

    4.单例模式详解 4.1.课程目标 1.掌握单例模式的应用场景. 2.掌握IDEA环境下的多线程调试方式. 3.掌握保证线程安全的单例模式策略. 4.掌握反射暴力攻击单例解决方案及原理分析. 5.序列 ...

  7. python单例模式解析_Python下简易的单例模式详解

    Python 下的单例模式 要点: 1.某个类只能有一个实例: 2.它必须自行创建这个实例: 3.它必须自行向整个系统提供这个实例 方法:重写new函数 应该考虑的情况: 1.这个单例的类可能继承了别 ...

  8. iOS 2D绘图详解(Quartz 2D)之路径(点,直线,虚线,曲线,圆弧,椭圆,矩形)

    前言:一个路径可以包含由一个或者多个shape以及子路径subpath,quartz提供了很多方便的shape可以直接调用.例如:point,line,Arc(圆弧),Curves(曲线),Ellip ...

  9. IOS 多线程04-GCD详解 底层并发 API

    IOS 多线程04-GCD详解 底层并发 API 注:本人是翻译过来,并且加上本人的一点见解. 前言 想要揭示出表面之下深层次的一些可利用的方面.这些底层的 API 提供了大量的灵活性,随之而来的是大 ...

最新文章

  1. [单刷APUE系列]第八章——进程控制[1]
  2. UILabel 调整行间距
  3. ios JSON 解析流程(转)
  4. AFIO时钟何时开启
  5. 经常在比特币中看到的merkle树是什么?
  6. Python的虚拟环境配置(pyenv+virtualenv)
  7. 无迹卡尔曼滤波(UKF)
  8. 洛谷——P3225 [HNOI2012]矿场搭建
  9. 软件测试工程师 Linux 十大场景命令使用
  10. html设置在父元素底部对齐,如何将div对齐到父元素的底部
  11. Memcached 集群架构方面的问题
  12. 双击java安装包没有反应_eclipse安装包双击没反应怎么回事?
  13. Postman 汉化包(设置中文)
  14. 首发丨极课大数据完成1亿元B轮融资,用AI提升学生作业、考试管理效率
  15. 一个app的流程分析
  16. Android 安卓动画 补间动画 - 缩放动画
  17. 可爱的狮子(lion)
  18. 配置虚拟机(VMware Workstation)静态 IP 地址
  19. fpu测试_解毒盖世G600散热器,3900X超频测试能不能压住?
  20. Nexus 05 第二种方式 使用Jenkins Nexus插件上传制品

热门文章

  1. VirtualBox中的网络连接方式详解
  2. 美团脱颖而出的经验_使数据科学项目脱颖而出的6种方法
  3. 零信任模型_关于信任模型
  4. 未来5年,中国会有多少企业营收能达到1000亿美元以上?
  5. php 终止程序的方法——return、exit()、die()
  6. 农村房屋能抵押做贷款吗?
  7. 日本电影《摇摆》:男人之间的心灵碰撞
  8. 单片机小白学步系列(十九) 单片机/计算机系统概述:扩展模块
  9. 推荐几个机器学习算法及应用领域相关的中国大牛:
  10. VS2008 SP1补丁