一.單例設計模式
1.單例模式:某一個類在所在應用程序中只有一個實例,將類的實例化限制成僅一個對象的設計模式。
2.static關鍵字:會在聲明變量的時候分配內存,在程序運行期間只分配一次內存。之后再訪問時,實際都是在訪問原先分配的內存;如果使用static來修飾局部變量,那么局部變量在代碼塊結束后將不會回收,下次使用保持上次使用后的值。如果使用static來修飾全局變量,那么表示該全局變量只在本文件中有效。static變量的作用域被限制在定義變量的當前文件中,其它文件是不能訪問,只能通過當前類的實例訪問。
3.單例是不可繼承,使用帶參數的宏完成通用版單例模式代碼,注意條件編譯的代碼不能包含在宏定義里面。
#import "NSManager.h"
@implementation NSManager
//提供一個static修飾的全局變量,強引用著已經實例化的單例對象實例
static NSManager *_instance;
static BOOL token = YES;
//類方法,返回一個單例對象
+ (instancetype)shareInstance
{
return [[self alloc]init];
}
//保證永遠只分配一次存儲空間
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
//兩種方式保證線程安全并只執行一次
? ? if (token)
? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? static dispatch_once_t onceToken;
? ? ? ? ? ? ? ? ? ? ? ? ? dispatch_once(&onceToken, ^{
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?_instance = [super allocWithZone:zone];
? ? ? ? ? ? ? ? ? ? ? ? ? ? });
? ? ? ?}else
? ? ? {
? ? ? ? ? @synchronized(self)
? ? ? ? ? ? {
? ? ? ? ? ? //保證只實例化一次
? ? ? ? ? ? ? ? ? ?if (_instance == nil)
? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ?//重寫allocWithZone方法 將實例_instance單獨放在一個內存池中進行內存操作
? ? ? ? ? ? ? ?_instance = [super allocWithZone:zone];
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ?}
? ? ? ? return _instance;
}
/*
[[ self alloc] init]; 調用時,會默認調用allocWithZone方法的? _instance 最終是在 allocWithZone方法中完成了初始化操作。
_instance = [super allocWithZone:zone];
原來allocWithZone是在給對象_instance分配內存空間。其中zone可以想象成一個內存池,alloc,allocWithZone或是dealloc這些操作,都是在這個內存池中操作的。cocoa總是會配置一個默認的NSZone,任何默認的內存操作都是在這個“zone”上操作的。默認的NSZone的缺陷在于,它是全局范圍的,時間一長,必然會導致內存的碎片化,如果你需要大量的alloc一些object,那么性能就會受到一些影響。
另外通過測試
alloc會默認調用allocWithZone方法
如果不重寫allocWithZone方法,在調用alloc和allocWithZone方法產生的實例可能不是同一個實例。因為會開辟新的內存空間
*/
/*
1. mutableCopy 創建一個新的可變對象,并初始化為原對象的值,新對象的引用計數為 1;
2. copy 返回一個不可變對象。分兩種情況:(1)若原對象是不可變對象,那么返回原對象,并將其引用計數加 1 ;(2)若原對象是可變對象,那么創建一個新的不可變對象,并初始化為原對象的值,新對象的引用計數為 1。
所以需要避免開辟新的內存空間 ?, 重寫copy方法并返回唯一實例。
*/
- (nonnull id)copyWithZone:(nullable NSZone *)zone
{
return _instance;
}
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
? ? ?return _instance;
}
@end
代碼地址:gitHub