一、什么是单例
单例就是,一个类,每次创建都是同一个对象。也就是说只能实例化一次。
二、如何保证每次创建都是同一个对象
创建一个对象归根揭底都会经过一个途径,alloc方法(alloc方法会调用allocWithZone:)。因此只要保证alloc方法只会调用一次,且保证线程安全,然后把此对象放在静态区。以后不管是创建对象还是copy对象都直接返回静态区的对象。
三、注意点
静态全局变量不需要考虑释放的问题(适用于MRC),解决线程安全问题可以用互斥锁或者GCD,后者更好。
也可设置不让对象重复初始化,即让初始化方法只能执行一次。
四、具体实现代码如下
@implementation myManager static id instance; + (instancetype)allocWithZone:(struct _NSZone *)zone { // 1、互斥锁 // @synchronized (self) { // if (instance == nil) // { // instance = [super allocWithZone:zone]; // } // } // 2、GCD,只执行一次 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (instance == nil) { instance = [super allocWithZone:zone]; } }); return instance; } + (instancetype)sharedSoundTools { instance = [[self alloc] init]; return instance; } - (id)copyWithZone:(NSZone *)zone { return instance; } #pragma mark - MRC 部分代码 - (oneway void)release { // 什么都不做 } - (instancetype)retain { // 本想什么都不做,但它要返回值 return instance; } - (instancetype)autorelease { return instance; } - (NSUInteger)retainCount { // 此处防止有人不明就里的粗暴释放对象,比如while循环 return ULONG_MAX; } - (instancetype)init { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ self = [super init]; if (self) { self.age = 10; // 只是举个例子,只初始化一次,可以不设置 } }); return self; } @end
五、单例宏
以下代码写在单独singleton.h文件里,使用时直接包含.h头文件。
使用方法,.h文件:singletonInterface(myManager);
.m文件:singletonImplementation(myManager);
抽取代码如下:
#define singletonInterface(className) + (instancetype)shared##className; #if __has_feature(objc_arc) // 以下是ARC版本 #define singletonImplementation(className) \ + (instancetype)allocWithZone:(struct _NSZone *)zone { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ if (instance == nil) { \ instance = [super allocWithZone:zone]; \ } \ }); \ return instance; \ } \ + (instancetype)shared##className { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ instance = [[self alloc] init]; \ }); \ return instance; \ } \ - (id)copyWithZone:(NSZone *)zone { \ return instance; \ } #else // 以下是MRC版本 #define singletonImplementation(className) \ + (instancetype)allocWithZone:(struct _NSZone *)zone { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ if (instance == nil) { \ instance = [super allocWithZone:zone]; \ } \ }); \ return instance; \ } \ + (instancetype)shared##className { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ instance = [[self alloc] init]; \ }); \ return instance; \ } \ - (id)copyWithZone:(NSZone *)zone { \ return instance; \ } \ - (oneway void)release {} \ - (instancetype)retain {return instance;} \ - (instancetype)autorelease {return instance;} \ - (NSUInteger)retainCount {return ULONG_MAX;} #endif // 提示末尾一行不要有 \
六、单例的两种模式
1、懒汉式,是在需要的时候再加载到内存。
2、饿汉式,会在最早的时间就把单例创建好,放入内存,随时可以使用。
// 饿汉式 @implementation HMSoundTools static id instance; // 只要程序运行,就会执行一次 + (void)load { instance = [[self alloc] init]; } // 第一次用到类或者子类的时候,会执行一次 //+ (void)initialize { // //} + (instancetype)sharedSoundTools { return instance; } - (id)copyWithZone:(NSZone *)zone { return instance; }