【iOS 单例设计模式】底层解析与运用
一、单例设计名词解释:
(官方解释)单例模式确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例。
(形象比喻)程序 — 公司 单例实例 - 管理员 单例设计模式就好比一家公司在创建到垮台 只招一个管理员。并且至始至终不换。当然这个管理员有直属的职责方法 [UIApplication sharedApplication].keyWindow 这里的UIApplication 就是管理员 sharedApplication 就是唯一的管理员身份怎么 keyWindow就是该管理员的职责方法。
二、常见的单例设计模式
[UIApplication sharedApplication]
[UIScreen mainScreen]
[NSUserDefaults standardUserDefaults]
垃圾箱
任务管理器
三、单例设计的使用建议
1、节省内存开销。如果某个对象需要被多个其它对象使用,那可以考虑使用单例,因为这样该类只使用一份内存资源。
2、使用单例,可以确保其它类只获取类的一份数据( 变量值 )。
优点
1、提供了对唯一实例的受控访问。
2、由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
3、因为单例模式的类控制了实例化的过程,所以类可以更加灵活修改实例化过程。
缺点
1、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
2、单例类的职责过重,在一定程度上违背了“单一职责原则”。
四、单例设计实践
1、线程不安全写法
1 #import "DanliManger.h" 2 3 static DanliManger *danliManger = nil; //定义一个全局的对象 4 @implementation DanliManger 5 6 + (DanliManger *)shareManger { 7 8 //此实例方法线程不安全,在多个实例同时加载的情况下。实例会同时创建 9 if (!danliManger) { 10 danliManger = [[DanliManger alloc] init]; 11 } 12 13 return danliManger; 14 } 15 16 @end
运行结果:
//执行方法 DanliManger *A = [DanliManger shareManger]; DanliManger *B = [DanliManger shareManger]; DanliManger *C = [[DanliManger alloc] init]; DanliManger *D = [[DanliManger alloc] init]; NSLog(@"\nA:%@\nB:%@\nC:%@\nD:%@",A,B,C,D); //下面是运行结果 A:<DanliManger: 0x17420ab90> B:<DanliManger: 0x17420ab90> C:<DanliManger: 0x17420aba0> D:<DanliManger: 0x17420abb0>
2、线程安全写法(推荐)
1 #import "DanLiManager_2.h" 2 3 @implementation DanLiManager_2 4 5 + (DanLiManager_2 *)shareManager { 6 7 static dispatch_once_t once; 8 static DanLiManager_2 *manager; 9 dispatch_once(&once, ^{ //线程只会执行一次,线程安全 10 manager = [[DanLiManager_2 myAlloc] init]; 11 }); 12 13 return manager; 14 } 15 16 +(instancetype)myAlloc{ 17 return [super allocWithZone:nil]; 18 } 19 20 +(instancetype)alloc{ 21 NSAssert(1, @"这是一个单例对象,请使用+(ZYHPayManager *)sharedMamager方法"); 22 return nil; 23 } 24 +(instancetype)allocWithZone:(struct _NSZone *)zone{ 25 return [self alloc]; 26 } 27 28 + (id)copy{ 29 NSLog(@"这是一个单例对象,copy将不起任何作用"); 30 return self; 31 } 32 33 +(instancetype)new{ 34 return [self alloc]; 35 } 36 37 @end
运行结果:
1 //执行方法 2 DanLiManager_2 *A21 = [DanLiManager_2 copy]; 3 DanLiManager_2 *A211 = [DanLiManager_2 new]; 4 DanLiManager_2 *A2 = [DanLiManager_2 shareManager]; 5 DanLiManager_2 *B2 = [DanLiManager_2 shareManager]; 6 DanLiManager_2 *C2 = [[DanLiManager_2 alloc] init]; 7 DanLiManager_2 *D2 = [[DanLiManager_2 alloc] init]; 8 NSLog(@"a12 %@ : a211%@",A21, A211); 9 NSLog(@"\nA2:%@\nB2:%@\nC2:%@\nD2:%@",A2,B2,C2,D2); 10 11 //运行结果 12 这是一个单例对象,copy将不起任何作用 13 a12 DanLiManager_2 : a211(null) 14 A2:<DanLiManager_2: 0x174015810> 15 B2:<DanLiManager_2: 0x174015810> 16 C2:(null) 17 D2:(null)
五、总结
从运行结果可以直观的看出。单例设计模式只有一个实例,线程安全。