iOS 单例模式

1. 单例模式的作用

  • 可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问
  • 从而方便地控制了实例个数,并节约系统资源

2. 单例模式的使用场合

  • 在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次)
  • 为防止单例模式滥用,下面几种情况可以不使用单例:
  • 仅仅使用一次的模块,可以不使用单例,可以采用在对应的周期内维护成员实例变量进行替换
  • 和状态无关的模块,可以采用静态(类)方法直接替换
  • 可以通过页面跳转进行依赖注入的模块,可以采用依赖注入或者变量传递等方式解决

3. ARC中,单例模式的实现

  • 1.在.m中保留一个全局的static的实例

    static id _instance;
  • 2.重写allocWithZone:方法,在这里创建唯一的实例

  • 使用dispatch_once 实现线程安全

  • 重写allocWithZone是为了使用 [ClassallocWithZone:nil]实例化对象时依旧只创建唯一实例

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });
    return _instance;
}
  • 3.提供1个类方法让外界访问唯一的实例
+ (instancetype)sharedInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}
  • 4.实现copyWithZone:方法
- (id)copyWithZone:(struct _NSZone *)zone
{
    return _instance;
}

4.ARC中完整版(GCD)

static id _instance;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
  static dispatch_once_t onceToken; // 必须是静态的
  dispatch_once(&onceToken, ^{
    _instance = [[super allocWithZone:zone] init]; // 记住这儿是super,不能用self
  });
  return _instance;
}
+ (instancetype)sharedPerson
{
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    _instance = [[self alloc] init];
  });
  return _instance;
}
// copyWithZone方法的前提是必须先有一个对象
- (id)copyWithZone:(NSZone *)zone
{
  return _instance;
}

  • 在实际开发中,一个应用程序可能有多个对象是单例对象,此时我们应该把 单例抽成一个宏放在一个单独的.h文件中 , 千万不能用继承

    • 其中 \ 表示此行跟下面一行是一起的
    • ## 表示后面是参数
    • 此时,注释只能在上面,在右边注释会报错的
// .h文件中的声明
#define SLInstanceH(name)  + (instancetype)shared##name;
// .m文件的实现
#define SLInstanceM(name) static id _instance; \
\
+ (instancetype)allocWithZone:(struct _NSZone *)zone\
{\
  static dispatch_once_t onceToken;\
  dispatch_once(&onceToken, ^{\
    _instance = [[super allocWithZone:zone] init];\
  });\
  return _instance;\
}\
\
+ (instancetype)shared##name\
{\
  static dispatch_once_t onceToken;\
  dispatch_once(&onceToken, ^{\
    _instance = [[self alloc] init];\
  });\
  return _instance;\
}\
\
- (id)copyWithZone:(NSZone *)zone\
{\
  return _instance;\
}
  • 使用宏的时候
  • 在.m文件中
#import <Foundation/Foundation.h>
#import "SLSharedInstance.h"  // 导入,定义了宏的.h文件

@interface SLPerson : NSObject<NSCopying>
SLInstanceH(Person)  // 传入单例的对象
@end
  • 在.h文件中
#import "SLPerson.h"

@implementation SLPerson
SLInstanceM(Person)
@end

5. 单例模式(常规做法,非GCD)

  • 一定要加互斥锁,不然会有线程安全问题
#import "SLPerson.h"
@implementation SLPerson
static id _instance;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
  @synchronized(self){ // 一定要加互斥锁,不然会有线程安全问题
    if (_instance == nil) {
      _instance = [[super allocWithZone:zone] init];
    }
  }
  return _instance;
}
+ (instancetype)sharedPerson
{
  @synchronized(self){
    if (_instance == nil) {
      _instance = [[self alloc] init];
    }
  }
  return _instance;
}
// 要有对象才能进行copy
- (id)copyWithZone:(NSZone *)zone
{
  return _instance;
}
@end

单例模式的参考内容:

滥用单例之dispatch_once死锁      http://satanwoo.github.io/

从 Objective-C 里的 Alloc 和 AllocWithZone 谈起           http://justinyan.me/post/1306

Objective-C中单例模式的实现 http://cocoa.venj.me/blog/singleton-in-objc/   


猜你喜欢

转载自blog.csdn.net/mrqingyu/article/details/51958033