單例模式在ARC中的實現(xiàn)
ARC實現(xiàn)單例步驟
- 在類的內(nèi)部提供一個
static
修飾的全局變量 - 提供一個類方法右锨,方便外界訪問
- 重寫
+allocWithZone
方法(注意線程安全)傅是,保證永遠都只為單例對象分配一次內(nèi)存空間 - 嚴謹起見察郁,重寫
-copyWithZone
方法和-MutableCopyWithZone
方法
注意: <NSCopying>的協(xié)議杨刨,并實現(xiàn)相應的方法,防止別人誤調(diào)copy方法而崩潰
ARC 單例實現(xiàn)源碼
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface CustomManager : NSObject
+ (instancetype)new NS_UNAVAILABLE; // 禁止使用
//命名規(guī)范 share+類名 | default+類名 | 類名
+ (instancetype)shareCustomManager;
@end
NS_ASSUME_NONNULL_END
@interface CustomManager ()<NSCopying>
@end
@implementation CustomManager
// 提供一個static修飾的全局變量,強引用著已經(jīng)實例化的單例對象實例(防止外部訪問)
static CustomManager *_manager;
// 類方法,返回一個單例對象
+(instancetype)shareCustomManager
{
// return _manager;
// 注意:這里建議使用self,而不是直接使用類名(考慮繼承)
return [[self alloc]init];
}
// new -> alloc -> allocWithZone 最終必須調(diào)用的方法
// 保證永遠只分配一次存儲空間
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
// 使用GCD中的一次性代碼
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_manager = [super allocWithZone:zone];
});
return _manager;
}
// 讓代碼更加的嚴謹 仇参,也要重寫copyWithZone 和 mutableCopyWithZone
- (id)copyWithZone:(nullable NSZone *)zone
{
return [[self class] allocWithZone:zone];
return _manager;
}
- (id)mutableCopyWithZone:(nullable NSZone *)zone
{
return _manager;
}
@end
單利創(chuàng)建的幾種方式
1、傳統(tǒng)方法
+ (instancetype)traditionSingleton{
static CustomManager *singleton = nil;
if (singleton == nil){
singleton = [[self alloc] init];
}
return singleton;
}
2婆殿、GCD方式
+ (instancetype)gcdSingleton{
static CustomManager *singleton = nil;
//給單例加了一個線程鎖
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[self alloc] init];
});
return singleton;
}
3诈乒、加鎖方式
為了防止多線程同時訪問對象,造成多次分配內(nèi)存空間婆芦,所以要加上線程鎖怕磨。
+ (instancetype)singleton{
static CustomManager *singleton = nil;
// 使用加鎖的方式,保證只分配一次存儲空間
if (singleton == nil) { //防止頻繁加鎖
@synchronized(self) {
if(singleton == nil) { //防止創(chuàng)建多次
singleton = [[self alloc] init];
}
}
}
return singleton;
}
擴展
Q:new -> alloc -> allocWithZone 最終必須調(diào)用的方法
A:通過打印方式查看調(diào)用方法消约;
+[CustomManager new]
+[CustomManager alloc]
+[CustomManager allocWithZone:]
說明
避免使用new創(chuàng)建對象肠鲫,從安全和設計角度來說我們應該對初始化所有屬性,提高程序的健壯性和復用性荆陆。
不論是何種情況滩届,在類中至少包含一個構造函數(shù)是一種很好的編程實踐,如果類中有屬性,好的實踐往往是初始化這些屬性帜消。
——以上摘自《The Object-Oriented Thought Process》 by Matt Weisfeld