设计模式-02-单例
完整的单例通常需要实现三个方法(GCD)
-
share方法
+ (instancetype)sharePerson { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _person = [[self alloc] init]; }); return _person; }
-
alloc方法
+ (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _person = [super allocWithZone:zone]; }); return _person; }
-
copy方法
- (id)copyWithZone:(NSZone *)zone { return _person; }
通过宏实现单例(GCD方式)
-
代码如下:
//.h文件 #define LYPSingletonH(name) + (instancetype)share##name; //.m文件 #define LYPSingletonM(name) \ static id _instance; \ \ + (instancetype)share##name \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [[self alloc] init]; \ }); \ return _instance; \ } \ \ + (instancetype)allocWithZone:(struct _NSZone *)zone \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [super allocWithZone:zone]; \ }); \ return _instance; \ } \ \ - (id)copyWithZone:(NSZone *)zone \ { \ return _instance; \ }
-
注意事项
- 每行后边的\表示下一行与该部分也是一个整体
- .h文件下的一行要加分号,否则在引用的时候要加分号
- 定义宏的新名字后边必须加空格,因为编译器,默认将新名字开始遇到的第一个空格前的部分作为宏的名字
通过非GCD方式实现单例
-
实现代码如下
static Dog *_dog; + (instancetype)shareDog { @synchronized(self) { if (_dog == nil) { [NSThread sleepForTimeInterval:3]; _dog = [[self alloc] init]; } } return _dog; } + (instancetype)allocWithZone:(struct _NSZone *)zone { @synchronized(self) { if (_dog == nil) { [NSThread sleepForTimeInterval:3]; _dog = [super allocWithZone:zone]; } } return _dog; } - (id)copyWithZone:(NSZone *)zone { return _dog; }
-
注意事项
- 为创建对象是分配内存和初始化的代码加锁,若不加锁,当多个线程并发执行创建对象任务,将会破坏单例模式,创建出多个对象(通常在创建对象耗时比较长的时候发生)
@synchronized(self) {}
- 为创建对象是分配内存和初始化的代码加锁,若不加锁,当多个线程并发执行创建对象任务,将会破坏单例模式,创建出多个对象(通常在创建对象耗时比较长的时候发生)
注意
1.单例模式不能使用继承实现,否则所有子类创建的对象都将是第一个创建的对象