单例在我们开发中是最常用的设计模式,在iOS中也是如此。单例可以保证某个类的实例在程序中是唯一的,便于进行资源和数据的共享。使用的设计原则是单一职责原则。我们来看看在iOS中本身自带的类或者方法哪些使用了单例的模式:

 

(1)UIAccelerometer类和sharedAccelerometer方法,一般如果方法名中有shared这样的词,就可以认为这是一个可以整个应用程序共享的实例变量,一般是使用了单例。

(2)UIApplication类和sharedApplication方法,我们一般使用该方法来创建全局变量。

(3)NSBundle类和mainBundle方法。

(4)NSFileManager类和defaultManager方法。

(5)NSNotificationCenter类和defaultManager方法。其中NSNotificationCenter也实现了观察者模式。

(6)NSUserDefaults类和defaultUser方法。

示例代码上传至:https://github.com/chenyufeng1991/iOS-Singleton


 

【单例实现】

(1)新建一个普通的类,假设名字为Singleton. 在Singleton.h中声明一个类方法,到时候使用该类方法(注意:一定是类方法,而不是实例方法)可以创建该类的唯一的一个实例:

 

  1. #import <Foundation/Foundation.h>
  2. @class Singleton;
  3. @interface Singleton : NSObject
  4. // "+" 表示类的方法,由类调用
  5. +(Singleton *)sharedInstance;
  6. @end


(2)在Singleton.m中需要实现sharedInstance方法和你其他的业务逻辑:

 

 

  1. #import "Singleton.h"
  2. // 用static声明一个类的静态实例;
  3. static Singleton *_sharedInstance = nil;
  4. @implementation Singleton
  5. /**
  6. * 1.使用类方法生成这个类唯一的实例;
  7. */
  8. +(Singleton *)sharedInstance{
  9. if (!_sharedInstance) {
  10. _sharedInstance =[[self alloc]init];
  11. }
  12. return _sharedInstance;
  13. }
  14. @end


注意:一定要声明一个static的静态变量。以后创建类的唯一实例就使用sharedInstance方法,而不是使用alloc ,init.

 


 

(3)我们使用一个简单的demo来演示一下单例:

 

  1. #import "RootVC.h"
  2. #import "Singleton.h"
  3. @interface RootVC ()
  4. @end
  5. @implementation RootVC
  6. - (void)viewDidLoad
  7. {
  8. [super viewDidLoad];
  9. [self testSigleTon];
  10. }
  11. -(void)testSigleTon
  12. {
  13. //单例的结果就是,调用类方法,只返回一个共有的对象
  14. /**
  15. * single和single2是同一个对象;
  16. 因为返回的数据是一个静态变量,全局唯一;
  17. */
  18. Singleton *single = [Singleton sharedInstance];
  19. Singleton *single2 = [Singleton sharedInstance];
  20. if (single == single2) {
  21. NSLog(@"single == single2");
  22. }
  23. NSLog(@"single地址:%@",single);
  24. NSLog(@"single2地址:%@",single2);
  25. }
  26. @end


(4)输出结果如下:

 


 


 

可以看到,两个对象的内存地址是一样的,表示这两个对象其实是同一个对象,单例也就实现了。这是单例最普遍也是最简单的实现方式,在项目中会经常用到,在不涉及多线程的情况下是完全正确的。但是,我们再多想一想,在多线程开发中,这种实现方式是否安全呢?那么应该如何实现。


 

【单例架构】

在项目开发中,如果我们像上述实现方法一样,在每个类中都使用这样写一个方法来生成单例,会不会显得很麻烦,很冗余。这样重复在每个类中重复写代码不利于开发与架构,那么我们应该使用什么方法来进行代码抽取呢?解决方案就是使用类别(Category)。关于Category类别的简要介绍,请参考《Objective-C——类别(Category)详解》。具体的实现如下:

(1)新建一个Category,作为对NSObject类的扩展。因为NSObject类是大部分iOS类的基类,如果使用Category为NSObject增加额外方法(shareInstance方法),那么所有继承自NSObject的类都可以使用该方法。我们常用的UIViewController和UIView都是从NSObject继承的,这样就会很方便。


 


 

(2)类别Category生成以后文件如下:

 


 

需要在NSObject+Singleton.h头文件中对外暴露一个生成实例的方法,供其他类调用。

 

  1. #import <Foundation/Foundation.h>
  2. @interface NSObject (Singleton)
  3. // "+" 表示类的方法,由类调用
  4. + (instancetype)sharedInstance;
  5. @end

 


 

(3)在NSObject+Singleton.m中需要实现上述方法,用来生成某一个类的唯一实例。我这里使用字典来存储某一个类和该类的实例,也就是键值对的形式:键是类名,值是对象。根据类名去检索该类的对象是否已经被创建,如果检索到类名,表示已经被创建,则直接返回对象;如果没有检索到类名,则需要创建,创建完成后也存储到字典中;

 

  1. #import "NSObject+Singleton.h"
  2. @impleme