一.單例設(shè)計(jì)模式
1.單例模式:某一個類在所在應(yīng)用程序中只有一個實(shí)例盲憎,將類的實(shí)例化限制成僅一個對象的設(shè)計(jì)模式善玫。
2.static關(guān)鍵字:會在聲明變量的時候分配內(nèi)存,在程序運(yùn)行期間只分配一次內(nèi)存粉私。之后再訪問時绷旗,實(shí)際都是在訪問原先分配的內(nèi)存;如果使用static來修飾局部變量,那么局部變量在代碼塊結(jié)束后將不會回收际乘,下次使用保持上次使用后的值坡倔。如果使用static來修飾全局變量,那么表示該全局變量只在本文件中有效脖含。static變量的作用域被限制在定義變量的當(dāng)前文件中罪塔,其它文件是不能訪問,只能通過當(dāng)前類的實(shí)例訪問。
3.單例是不可繼承养葵,使用帶參數(shù)的宏完成通用版單例模式代碼,注意條件編譯的代碼不能包含在宏定義里面征堪。
#import "NSManager.h"
@implementation NSManager
//提供一個static修飾的全局變量,強(qiáng)引用著已經(jīng)實(shí)例化的單例對象實(shí)例
static NSManager *_instance;
static BOOL token = YES;
//類方法关拒,返回一個單例對象
+ (instancetype)shareInstance
{
return [[self alloc]init];
}
//保證永遠(yuǎn)只分配一次存儲空間
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
//兩種方式保證線程安全并只執(zhí)行一次
? ? if (token)
? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? static dispatch_once_t onceToken;
? ? ? ? ? ? ? ? ? ? ? ? ? dispatch_once(&onceToken, ^{
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?_instance = [super allocWithZone:zone];
? ? ? ? ? ? ? ? ? ? ? ? ? ? });
? ? ? ?}else
? ? ? {
? ? ? ? ? @synchronized(self)
? ? ? ? ? ? {
? ? ? ? ? ? //保證只實(shí)例化一次
? ? ? ? ? ? ? ? ? ?if (_instance == nil)
? ? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ?//重寫allocWithZone方法 將實(shí)例_instance單獨(dú)放在一個內(nèi)存池中進(jìn)行內(nèi)存操作
? ? ? ? ? ? ? ?_instance = [super allocWithZone:zone];
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ?}
? ? ? ? return _instance;
}
/*
[[ self alloc] init]; 調(diào)用時佃蚜,會默認(rèn)調(diào)用allocWithZone方法的? _instance 最終是在 allocWithZone方法中完成了初始化操作。
_instance = [super allocWithZone:zone];
原來allocWithZone是在給對象_instance分配內(nèi)存空間着绊。其中zone可以想象成一個內(nèi)存池谐算,alloc,allocWithZone或是dealloc這些操作,都是在這個內(nèi)存池中操作的归露。cocoa總是會配置一個默認(rèn)的NSZone洲脂,任何默認(rèn)的內(nèi)存操作都是在這個“zone”上操作的。默認(rèn)的NSZone的缺陷在于剧包,它是全局范圍的恐锦,時間一長往果,必然會導(dǎo)致內(nèi)存的碎片化,如果你需要大量的alloc一些object一铅,那么性能就會受到一些影響陕贮。
另外通過測試
alloc會默認(rèn)調(diào)用allocWithZone方法
如果不重寫allocWithZone方法,在調(diào)用alloc和allocWithZone方法產(chǎn)生的實(shí)例可能不是同一個實(shí)例馅闽。因?yàn)闀_辟新的內(nèi)存空間
*/
/*
1. mutableCopy 創(chuàng)建一個新的可變對象飘蚯,并初始化為原對象的值,新對象的引用計(jì)數(shù)為 1福也;
2. copy 返回一個不可變對象局骤。分兩種情況:(1)若原對象是不可變對象,那么返回原對象暴凑,并將其引用計(jì)數(shù)加 1 峦甩;(2)若原對象是可變對象,那么創(chuàng)建一個新的不可變對象现喳,并初始化為原對象的值凯傲,新對象的引用計(jì)數(shù)為 1。
所以需要避免開辟新的內(nèi)存空間 ?嗦篱, 重寫copy方法并返回唯一實(shí)例冰单。
*/
- (nonnull id)copyWithZone:(nullable NSZone *)zone
{
return _instance;
}
- (nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
? ? ?return _instance;
}
@end
代碼地址:gitHub