單例模式在iOS開發中可能算是最經常使用的模式之一了,可是因爲OC自己的語言特性,想要寫一個正確的單例模式相對來講比較麻煩. 今天就來講一說, 單例建立的方式和嚴謹的單例寫法及可繼承單例編寫.ios
SingleHandle.hatom
@interface SingleHandle : NSObject //單例建立方法通常以 share, stand, main 開頭 + 當前類名 +(SingleHandle *)shareSingleHandle; @end
SingleHandle.mspa
@implementation SingleHandle //聲明靜態變量 static SingleHandle *singlehanle = nil; +(SingleHandle *)shareSingleHandle { //同步鎖 //防止一種極限的可能,第一個對象正在建立的時候,第二個對象就開始建立了,形成兩個對象 @synchronized(self){ if (singlehanle == nil) { singlehanle = [[SingleHandle alloc]init]; } return singlehanle; } } @end
Singleton.h.net
@interface Singleton : NSObject +(instancetype) shareInstance; @end
Singleton.mcode
@implementation Singleton static Singleton* instance = nil; +(instancetype) shareInstance { static dispatch_once_t onceToken ; dispatch_once(&onceToken, ^{ instance = [[self alloc] init] ; }) ; return instance ; } @end
通常狀況下,可能咱們寫的單例模式是上面的方式, 這裏再也不贅述, 但這樣是不嚴謹的. 先來看一下到底不嚴謹的寫法缺點是什麼.
以上面的方式二舉例:對象
Singleton* single1 = [Singleton shareInstance] ; NSLog(@"single1 = %@", single1) ; Singleton* single2 = [Singleton shareInstance] ; NSLog(@"single2 = %@", single2) ; Singleton* single3 = [[Singleton alloc] init] ; NSLog(@"single3 = %@", single3) ; NSLog(@"single4 = %@", [single3 copy]) ;
打印結果:繼承
single1 = < Singleton: 0x7ffb93743e80 > single2 = < Singleton: 0x7ffb93743e80 > single3 = < Singleton: 0x7ffb9373ecc0 > -[Singleton copyWithZone:]: unrecognized selector sent to instance 0x7ffb9373ecc0
能夠看到,當咱們調用shareInstance方法時獲取到的對象是相同的,可是當咱們經過alloc和init來構造對象的時候,獲得的對象倒是不同的。並且在 single4 這行註釋打開後, 會在此崩潰, 緣由如上. 內存
因此,咱們經過不一樣的途徑獲得不一樣的對象,顯然是不行的。咱們必需要確保對象的惟一性,因此咱們就須要封鎖用戶經過alloc和init以及copy來構造對象這條道路。ci
咱們知道,建立對象的步驟分爲申請內存(alloc)、初始化(init)這兩個步驟,咱們要確保對象的惟一性,所以在第一步這個階段咱們就要攔截它。當咱們調用alloc方法時,OC內部會調用allocWithZone這個方法來申請內存,咱們覆寫這個方法,而後在這個方法中調用shareInstance方法返回單例對象,這樣就能夠達到咱們的目的。拷貝對象也是一樣的原理,覆寫copyWithZone方法,而後在這個方法中調用shareInstance方法返回單例對象。開發
@implementation Singleton static Singleton* instance = nil; +(instancetype) shareInstance { static dispatch_once_t onceToken ; dispatch_once(&onceToken, ^{ instance = [[super allocWithZone:NULL] init]; }) ; return instance ; } +(id) allocWithZone:(struct _NSZone *)zone { return [Singleton shareInstance] ; } -(id) copyWithZone:(struct _NSZone *)zone { return [Singleton shareInstance] ; } @end
打印結果:
single1 = < Singleton: 0x7fe2e24a2880 > single2 = < Singleton: 0x7fe2e24a2880 > single3 = < Singleton: 0x7fe2e24a2880 > single4 = < Singleton: 0x7fe2e24a2880 >
這樣就是比較正確很嚴謹的寫法了.
可繼承單例是指父類中寫下單例建立的方法, 當其自己類或其子類調用父類中的類建立的方法時, 能夠各自類建立各自類的單例. 因此, 在父類中寫的一個方法, 同時適用於其自己和其子類, 故稱做可繼承單例.
單例類 A :
@interface A : NSObject @property (nonatomic,copy)NSString *a1; + (instancetype)sharedInstance; @end #import "A.h" #import <objc/runtime.h> @implementation A +(instancetype)sharedInstance { id instance = objc_getAssociatedObject(self, @"instance"); if (!instance) { instance = [[super allocWithZone:NULL] init]; NSLog(@"單例建立=====%@=====",instance); objc_setAssociatedObject(self, @"instance", instance, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } return instance; } +(id) allocWithZone:(struct _NSZone *)zone { return [self sharedInstance] ; } -(id) copyWithZone:(struct _NSZone *)zone { Class selfClass = [self class]; return [selfClass sharedInstance] ; } @end
單例類 B 和單例類 C 中無任何方法和屬性, 只是繼承於A類.
執行下面的方法:
A *singleA = [A sharedInstance]; B *singleB = [B sharedInstance]; C *singleC = [C sharedInstance]; singleA.a1 = @"aaa"; singleB.a1 = @"bbb"; singleC.a1 = @"ccc"; NSLog(@"singleA = %p",singleA); NSLog(@"singleB = %p",singleB); NSLog(@"singleC = %p",singleC); NSLog(@"singleA.a1 = %@",singleA.a1); NSLog(@"singleB.b1 = %@",singleB.a1); NSLog(@"singleC.c1 = %@",singleC.a1);
打印結果:
單例建立=====< A: 0x7fc21282fb60 >===== 單例建立=====< B: 0x7fc21282fcb0 >===== 單例建立=====< C: 0x7fc210427190 >===== singleA = 0x7fc21282fb60 singleB = 0x7fc21282fcb0 singleC = 0x7fc210427190 singleA.a1 = aaa singleB.a1 = bbb singleC.a1 = ccc