单例模式是23种设计模式中较容易实现的设计模式之一,目的是为了在程序运行时只产生一个对象,应用场景主要是1、类只能有一个实例,而且必须从一个为人熟知的访问点对其访问。2、这个唯一的实例只能通过子类化进行扩展,而且扩展的对象不会破坏客户端代码。3、主要应用于工具类和调用次数比较多的类。我们这里只介绍在ARC模式下的单例模式,下面给出两种最典型的OC语言单例模式的代码:
一、不使用GCD的单例模式
头文件
1 // 2 // DataTool.h 3 // 02-单例模式 4 // 5 // Created by zhangjing on 15/7/5. 6 // Copyright (c) 2015年 zhangjing. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface DataTool : NSObject 12 + (instancetype)sharedDataTool; 13 @end
实现文件
1 // 2 // DataTool.m 3 // 02-单例模式 4 // 5 // Created by zhangjing on 15/7/5. 6 // Copyright (c) 2015年 zhangjing. All rights reserved. 7 // 8 9 #import "DataTool.h" 10 11 @implementation DataTool 12 static id _instance; 13 14 /** 15 * alloc方法内部会调用这个方法 16 */ 17 + (id)allocWithZone:(struct _NSZone *)zone 18 { 19 if (_instance == nil) { // 防止频繁加锁 20 @synchronized(self) { 21 if (_instance == nil) { // 防止创建多次 22 _instance = [super allocWithZone:zone]; 23 } 24 } 25 } 26 return _instance; 27 } 28 29 + (instancetype)sharedDataTool 30 { 31 if (_instance == nil) { // 防止频繁加锁 32 @synchronized(self) { 33 if (_instance == nil) { // 防止创建多次 34 _instance = [[self alloc] init]; 35 } 36 } 37 } 38 return _instance; 39 } 40 41 - (id)copyWithZone:(NSZone *)zone 42 { 43 return _instance; 44 } 45 @end
二、使用GCD的单例模式
引入GCD后我们将不再担心多线程的问题,也不用在代码中显式的为生成对象代码段上锁
头文件
1 // 2 // GCDDataTool.h 3 // 02-单例模式 4 // 5 // Created by zhangjing on 15/7/5. 6 // Copyright (c) 2015年 zhangjing. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 11 @interface GCDDataTool : NSObject 12 + (instancetype)sharedGCDDataTool; 13 @end
实现文件
1 // 2 // GCDDataTool.m 3 // 02-单例模式 4 // 5 // Created by zhangjing on 15/7/5. 6 // Copyright (c) 2015年 zhangjing. All rights reserved. 7 // 8 9 #import "GCDDataTool.h" 10 11 @implementation GCDDataTool 12 static id _instace; 13 14 + (id)allocWithZone:(struct _NSZone *)zone 15 { 16 static dispatch_once_t onceToken; 17 dispatch_once(&onceToken, ^{ 18 _instace = [super allocWithZone:zone]; 19 }); 20 return _instace; 21 } 22 23 + (instancetype)sharedGCDDataTool 24 { 25 static dispatch_once_t onceToken; 26 dispatch_once(&onceToken, ^{ 27 _instace = [[self alloc] init]; 28 }); 29 return _instace; 30 } 31 32 - (id)copyWithZone:(NSZone *)zone 33 { 34 return _instace; 35 } 36 37 @end
以上是单例模式最常见的实现的两种方式,因为代码比较成型,所以我们可以简化一下。
1 // .h文件 2 #define SingletonH(name) + (instancetype)shared##name; 3 4 // .m文件 5 #if __has_feature(objc_arc) 6 7 #define SingletonM(name) 8 static id _instace; 9 10 + (id)allocWithZone:(struct _NSZone *)zone 11 { 12 static dispatch_once_t onceToken; 13 dispatch_once(&onceToken, ^{ 14 _instace = [super allocWithZone:zone]; 15 }); 16 return _instace; 17 } 18 19 + (instancetype)shared##name 20 { 21 static dispatch_once_t onceToken; 22 dispatch_once(&onceToken, ^{ 23 _instace = [[self alloc] init]; 24 }); 25 return _instace; 26 } 27 28 - (id)copyWithZone:(NSZone *)zone 29 { 30 return _instace; 31 } 32 33 #else 34 35 #define SingletonM(name) 36 static id _instace; 37 38 + (id)allocWithZone:(struct _NSZone *)zone 39 { 40 static dispatch_once_t onceToken; 41 dispatch_once(&onceToken, ^{ 42 _instace = [super allocWithZone:zone]; 43 }); 44 return _instace; 45 } 46 47 + (instancetype)shared##name 48 { 49 static dispatch_once_t onceToken; 50 dispatch_once(&onceToken, ^{ 51 _instace = [[self alloc] init]; 52 }); 53 return _instace; 54 } 55 56 - (id)copyWithZone:(NSZone *)zone 57 { 58 return _instace; 59 } 60 61 - (oneway void)release { } 62 - (id)retain { return self; } 63 - (NSUInteger)retainCount { return 1;} 64 - (id)autorelease { return self;} 65 66 #endif
调用示例
头文件
1 // 2 // SDataTool.h 3 // 02-单例模式 4 // 5 // Created by zhangjing on 15/7/5. 6 // Copyright (c) 2015年 zhangjing. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 #import "Singleton.h" 11 12 @interface SDataTool : NSObject 13 SingletonH(SDataTool); 14 15 @end
实现文件
1 // 2 // SDataTool.m 3 // 02-单例模式 4 // 5 // Created by zhangjing on 15/7/5. 6 // Copyright (c) 2015年 zhangjing. All rights reserved. 7 // 8 9 #import "SDataTool.h" 10 11 @implementation SDataTool 12 SingletonM(SDataTool); 13 14 @end
注:我们也可以把引用写在.pch文件中
例如
1 // 2 // PrefixHeader.pch 3 // 03——单例模式IOS 4 // 5 // Created by zhangjing on 15/7/5. 6 // Copyright (c) 2015年 zhangjing. All rights reserved. 7 // 8 9 10 #ifdef __OBJC__//如果是OC语言文件 11 #import "Singleton.h" 12 #endif
这样在其他OC语言文件中就不用特意引用了