单例模式是iOS开发中最常用到的模式之一,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。但是单例的优缺点都非常明显。优点是在内存中只有一个实例,减少了内存的开销,能全局共享数据,降低代码耦合;缺点是无法继承,单例创建后内存不能释放。
普通单例
通常很多人写单例的时候只是用GCD创建了一个对象,通过静态变量去引用来实现单例。
/**静态单例对象 */
static LJManager *defaultManager = nil;
/**用dispatch_once确保单例对象只被创建一次 */
+ (LJManager *)defaultManager {
static dispatch_once_t token;
dispatch_once(&token, ^{
if(defaultManager == nil) {
defaultManager = [[self alloc] init];
}
});
return defaultManager;
}
严格单例
但是这样写并不能保证该类不创建其他的实例。要确保单例类创建出来的实例有且只有一个,就需要用严格单例来实现。
/**通过重写allocWithZone:方法,保证[[Singleton alloc] init]创建对象时对象的唯一性
*/
+ (id)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t token;
dispatch_once(&token, ^{
if(defaultManager == nil) {
defaultManager = [super allocWithZone:zone];
}
});
return defaultManager;
}
弱单例
虽然通过这种方式使单例对象成为了唯一实例,但是因为单例对象内存不能释放,而有时候我们又并不需要用到单例,比如当用户跳到地图模块的时候,我们会创建一个地图管理的单例,但是当用户退出地图时,这个单例其实就没有用了。这个时候我们就可以通过用弱单例的方式去实现在退出某个模块时释放单例。
/** 静态单例弱对象 */
static __weak LJManager *defaultManager;
/** 静态单例对象弱引用一个局部变量,当局部变量释放时,单例所指向的对象就会释放 */
+ (LJManager *)manager {
LJManager *manager = defaultManager;
@synchronized (self) {
if (manager == nil) {
@synchronized (self) {
manager = [[self alloc] init];
defaultManager = manager;
}
}
}
return manager;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
LJManager *manager = defaultManager;
@synchronized (self) {
if (manager == nil) {
@synchronized (self) {
manager = [super allocWithZone:zone];
defaultManager = manager;
}
}
}
return manager;
}
这时,当用户进入到地图模块时,地图主控制器通过属性去引用单例对象,当用户退出地图时,控制器被释放,属性所引用的单例对象也会被释放。这样就可以实现单例对象内存的释放了。