1.ios的單例模式有兩種官方寫法:
1)不使用GCD的方式
#import ?"Manager.h"
static ? Manager ? *manager;
@implementation ?Manager
+(Manager *))shareManager {
? ? ? ? ?if (!manager) {
? ? ? ? ? ? ? ? ? ?manager = [super ?allocWithZone:NULL] ?init];
? ? ? ? ? }
? ? ? ? ?return manager;
}
@end;
2)使用GCD的方式
#import ?"Manager.h"?
@implementataion ?Manager?
+(Manager *)shareManager {
? ? ? ? ? ? ?static ?Manager *shareManager;
? ? ? ? ? ? ? static dispatch_once_t? predicate;
? ? ? ? ? ? ?dispatch_once(&predicate, ^{
? ? ? ? ? ? ? ? ? ? ? ? shareManager =[super? allocWithZone:NULL]? init];
? ? ? ? ? ?});
? ? ? ? ? return ? shareManager;
}
//注明:dispatch_once這個函數,他可以一次保證整個應用程序生命周期中某段代碼只被執行
//不是使用alloc 方法,而是調用[super? allocWithZone:NULL]? init]; 已經重載allocWithZone基本的對象分配方法,所以要借用父類(NSObject)的功能來幫助處理底層內存分配的雜物
當我們調用shareManager方法時獲取到的對象是相同的,但是但當我們通過alloc和init以及copy來構造對象依然會創建新的實例。確保對象的唯一,需要封鎖用戶通過alloc和init以及copy來構造這條道路。創建對象的步驟分為申請內存(alloc)、初始化(init),要確保對象的唯一性,在第一步這個階段我們就要攔截它,當我們調用alloc方法時,oc內部會調用allocWithZone這個方法來申請內存,我們覆寫這個方法,然后在這個方法調用shareManager返回單例對象。
+(id)allocWithZone:(struct _NSZone *)zone {
? ? ? ? ? ? ? ? ?return ? ? [Manager ? ?shareManager];
}
-(id)copyWithZone:(NSZone *)zone {
? ? ? ? ? ?return? ? [Manager? ? shareManager];
}
-(id)mutablecopyWithZone:(NSZone *)zone {
? ? ? ? ? ?return? ? [Manager? ? shareManager];
}
@end
2.alloc和allocWithZone
在初始化一個對象時([Class alloc] ?init];)其實做了兩件事,alloc給對象分配內存空間,init是對對象的初始化,包括設置成員變量初始值這些工作。
而給對象分配內存空間,除了alloc方法之外還有另一個方法:allocWithZone.在NSObject類的官方文檔里面,allocWithZone方法介紹說,該方法的參數是被忽略的,正確的做法是傳nil或者NULL參數給他。(這個方法存在是歷史遺留原因,文檔里memory zone已經被棄用了,只是歷史原因才保留這個接口)
實踐證明,alloc方法初始化一個類的實例時,默認調用allocWithZone的方法,為了保持單例實例的唯一性需要覆蓋所有會生成新的實例方法,如果有人初始化這個單例的時候不走allocWithZone,而是直接[Class ?alloc] ?init]; ,那么這個單例就不再是單例了,所以把這個方法堵上
3.NSZone?