iOS開(kāi)發(fā)-單例模式

1.單例模式

  • 1.1 概念相關(guān)

(1)單例模式

在程序運(yùn)行過(guò)程喜滨,一個(gè)類只有一個(gè)實(shí)例

(2)使用場(chǎng)合

在整個(gè)應(yīng)用程序中径荔,共享一份資源(這份資源只需要?jiǎng)?chuàng)建初始化1次)
  • 1.2 ARC實(shí)現(xiàn)單例

(1)步驟

01 在類的內(nèi)部提供一個(gè)static修飾的全局變量
02 提供一個(gè)類方法胧后,方便外界訪問(wèn)
03 重寫(xiě)+allocWithZone方法,保證永遠(yuǎn)都只為單例對(duì)象分配一次內(nèi)存空間
04 嚴(yán)謹(jǐn)起見(jiàn)鲁豪,重寫(xiě)-copyWithZone方法和-MutableCopyWithZone方法

(2)相關(guān)代碼

//提供一個(gè)static修飾的全局變量,強(qiáng)引用著已經(jīng)實(shí)例化的單例對(duì)象實(shí)例
static Tools *_instance;

//類方法榔幸,返回一個(gè)單例對(duì)象
+(instancetype)shareTools
{
     //注意:這里建議使用self,而不是直接使用類名Tools(考慮繼承)

    return [[self alloc]init];
}

//保證永遠(yuǎn)只分配一次存儲(chǔ)空間
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
    //使用GCD中的一次性代碼
//    static dispatch_once_t onceToken;
//    dispatch_once(&onceToken, ^{
//        _instance = [super allocWithZone:zone];
//    });

    //使用加鎖的方式坊谁,保證只分配一次存儲(chǔ)空間
    @synchronized(self) {
        if (_instance == nil) {
            _instance = [super allocWithZone:zone];
        }
    }
    return _instance;
}
/*
1. mutableCopy 創(chuàng)建一個(gè)新的可變對(duì)象,并初始化為原對(duì)象的值隙袁,新對(duì)象的引用計(jì)數(shù)為 1痰娱;
2. copy 返回一個(gè)不可變對(duì)象。分兩種情況:
(1)若原對(duì)象是不可變對(duì)象菩收,那么返回原對(duì)象梨睁,并將其引用計(jì)數(shù)加 1 ;
(2)若原對(duì)象是可變對(duì)象娜饵,那么創(chuàng)建一個(gè)新的不可變對(duì)象坡贺,并初始化為原對(duì)象的值,新對(duì)象的引用計(jì)數(shù)為 1箱舞。
*/
//讓代碼更加的嚴(yán)謹(jǐn)
-(nonnull id)copyWithZone:(nullable NSZone *)zone
{
//    return [[self class] allocWithZone:zone];
    return _instance;
}

-(nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
    return _instance;
}

  • 1.3 MRC實(shí)現(xiàn)單例

(1)實(shí)現(xiàn)步驟

01 在類的內(nèi)部提供一個(gè)static修飾的全局變量
02 提供一個(gè)類方法遍坟,方便外界訪問(wèn)
03 重寫(xiě)+allocWithZone方法,保證永遠(yuǎn)都只為單例對(duì)象分配一次內(nèi)存空間
04 嚴(yán)謹(jǐn)起見(jiàn)晴股,重寫(xiě)-copyWithZone方法和-MutableCopyWithZone方法
05 重寫(xiě)release方法
06 重寫(xiě)retain方法
07 建議在retainCount方法中返回一個(gè)最大值

(2)配置MRC環(huán)境知識(shí)

01 注意ARC不是垃圾回收機(jī)制愿伴,是編譯器特性
02 配置MRC環(huán)境:build setting ->搜索automatic ref ->修改為NO

(3)相關(guān)代碼

//提供一個(gè)static修飾的全局變量,強(qiáng)引用著已經(jīng)實(shí)例化的單例對(duì)象實(shí)例
static Tools *_instance;

//類方法电湘,返回一個(gè)單例對(duì)象
+(instancetype)shareTools
{
     //注意:這里建議使用self,而不是直接使用類名Tools(考慮繼承)

    return [[self alloc]init];
}

//保證永遠(yuǎn)只分配一次存儲(chǔ)空間
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
    //使用GCD中的一次性代碼
//    static dispatch_once_t onceToken;
//    dispatch_once(&onceToken, ^{
//        _instance = [super allocWithZone:zone];
//    });

    //使用加鎖的方式隔节,保證只分配一次存儲(chǔ)空間
    @synchronized(self) {
        if (_instance == nil) {
            _instance = [super allocWithZone:zone];
        }
    }
    return _instance;
}

//讓代碼更加的嚴(yán)謹(jǐn)
-(nonnull id)copyWithZone:(nullable NSZone *)zone
{
//    return [[self class] allocWithZone:zone];
    return _instance;
}

-(nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
    return _instance;
}

//在MRC環(huán)境下鹅经,如果用戶retain了一次,那么直接返回instance變量怎诫,不對(duì)引用計(jì)數(shù)器+1
//如果用戶release了一次瘾晃,那么什么都不做,因?yàn)閱卫J皆谡麄€(gè)程序運(yùn)行過(guò)程中都擁有且只有一份刽虹,程序退出之后被釋放酗捌,所以不需要對(duì)引用計(jì)數(shù)器操作
-(oneway void)release
{
}

-(instancetype)retain
{
    return _instance;
}

//慣用法,有經(jīng)驗(yàn)的程序員通過(guò)打印retainCount這個(gè)值可以猜到這是一個(gè)單例
-(NSUInteger)retainCount
{
    return MAXFLOAT;
}

  • 1.4 通用版本

(1)有意思的對(duì)話

01 問(wèn):寫(xiě)一份單例代碼在ARC和MRC環(huán)境下都適用涌哲?
答:可以使用條件編譯來(lái)判斷當(dāng)前項(xiàng)目環(huán)境是ARC還是MRC
02 問(wèn):條件編譯的代碼呢胖缤,么么噠?
//答:條件編譯
#if __has_feature(objc_arc)
//如果是ARC阀圾,那么就執(zhí)行這里的代碼1
#else
//如果不是ARC哪廓,那么就執(zhí)行代理的代碼2
#endif
03 問(wèn):在項(xiàng)目里面往往需要實(shí)現(xiàn)很多的單例,比如下載初烘、網(wǎng)絡(luò)請(qǐng)求涡真、音樂(lè)播放等等,弱弱的問(wèn)一句單例可以用繼承嗎肾筐?
答:?jiǎn)卫遣豢梢杂美^承的哆料,如果想一次寫(xiě)就,四處使用吗铐,那么推薦親使用帶參數(shù)的宏定義啦东亦!
04 問(wèn):宏定義怎么弄?

#define SingleH(name) +(instancetype)share##name;

#if __has_feature(objc_arc)
// ARC
#define SingleM(name) \
static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
   static dispatch_once_t onceToken;\
   dispatch_once(&onceToken, ^{\
      _instance = [super allocWithZone:zone];\
   });\
   return _instance;\
}\
\
+(instancetype)share##name\
{\
   return [[self alloc]init];\
}\
\
-(id)copyWithZone:(NSZone *)zone\
{\
   return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
   return _instance;\
}
#else
// MRC
#define SingleM(name) \
static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone\
{\
   static dispatch_once_t onceToken;\
   dispatch_once(&onceToken, ^{\
      _instance = [super allocWithZone:zone];\
   });\
   return _instance;\
}\
\
+(instancetype)share##name\
{\
   return [[self alloc]init];\
}\
\
-(id)copyWithZone:(NSZone *)zone\
{\
   return _instance;\
}\
\
-(id)mutableCopyWithZone:(NSZone *)zone\
{\
   return _instance;\
}\
-(oneway void)release\
{\
}\
\
-(instancetype)retain\
{\
    return _instance;\
}\
\
-(NSUInteger)retainCount\
{\
    return MAXFLOAT;\
}
#endif

(2)使用帶參數(shù)的宏完成通用版單例模式代碼

01 注意條件編譯的代碼不能包含在宏定義里面
02 宏定義的代碼只需要寫(xiě)一次就好唬渗,之后直接拖到項(xiàng)目中用就OK
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末典阵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子镊逝,更是在濱河造成了極大的恐慌壮啊,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撑蒜,死亡現(xiàn)場(chǎng)離奇詭異歹啼,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)座菠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門染突,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人辈灼,你說(shuō)我怎么就攤上這事∫查” “怎么了巡莹?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵司志,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我降宅,道長(zhǎng)骂远,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任腰根,我火速辦了婚禮激才,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘额嘿。我一直安慰自己瘸恼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布册养。 她就那樣靜靜地躺著东帅,像睡著了一般。 火紅的嫁衣襯著肌膚如雪球拦。 梳的紋絲不亂的頭發(fā)上靠闭,一...
    開(kāi)封第一講書(shū)人閱讀 52,807評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音坎炼,去河邊找鬼愧膀。 笑死,一個(gè)胖子當(dāng)著我的面吹牛谣光,可吹牛的內(nèi)容都是我干的檩淋。 我是一名探鬼主播,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼抢肛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼狼钮!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起捡絮,我...
    開(kāi)封第一講書(shū)人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤熬芜,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后福稳,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體涎拉,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年的圆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鼓拧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡越妈,死狀恐怖季俩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情梅掠,我是刑警寧澤酌住,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布店归,位于F島的核電站,受9級(jí)特大地震影響酪我,放射性物質(zhì)發(fā)生泄漏消痛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一都哭、第九天 我趴在偏房一處隱蔽的房頂上張望秩伞。 院中可真熱鬧,春花似錦欺矫、人聲如沸纱新。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)怒炸。三九已至,卻和暖如春毡代,著一層夾襖步出監(jiān)牢的瞬間阅羹,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工教寂, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捏鱼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓酪耕,卻偏偏與公主長(zhǎng)得像导梆,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子迂烁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容