iOS設(shè)計(jì)模式淺析之單例模式(Singleton)

  • 1.1 概念

(1)單例模式

(1.1)在程序運(yùn)行過程,一個(gè)類只有一個(gè)實(shí)例伍纫,而且該實(shí)例易于供外界訪問
(1.2)方便地控制了實(shí)例個(gè)數(shù)莹规,并節(jié)約系統(tǒng)資源
(1.3)單例是不可以用繼承的,因?yàn)椴荒芨割惻c子類共用一個(gè)全局變量

(2)使用場合

在整個(gè)應(yīng)用程序中舞虱,共享一份資源(這份資源只需要?jiǎng)?chuàng)建初始化1次)母市;
可以理解為當(dāng)需要一個(gè)24小時(shí)響應(yīng)的“馬仔”幫你實(shí)現(xiàn)某些功能時(shí),使用單例焕刮。

(3)約束-不要濫用單例模式

1. 單例是一種全局狀態(tài)配并,意味著App的任何地方都可以和這個(gè)單例進(jìn)行交互高镐,無形中增加了代碼的耦合
2. 單例的生命周期難以控制,雖然可以在單例中提供方法設(shè)為nil進(jìn)行釋放观腊。
  • 1.2 實(shí)現(xiàn)單例(在ARC與MRC中均可執(zhí)行)

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

01 在類的內(nèi)部提供一個(gè)static修飾的全局變量
02 重寫+allocWithZone方法算行,保證永遠(yuǎn)都只為單例對(duì)象分配一次內(nèi)存空間
03 提供一個(gè)類方法,方便外界訪問
04 嚴(yán)謹(jǐn)起見州邢,重寫-copyWithZone方法和-MutableCopyWithZone方法
05 通過條件編譯判斷是否是ARC{__has_feature(objc_arc)}儡陨,若是,則不再執(zhí)行代碼量淌,否則執(zhí)行下述06-09代碼
06 重寫release方法
07 重寫retain方法
08 建議在retainCount方法中返回一個(gè)最大值
09 結(jié)束條件編譯

(2)如果在MRC中運(yùn)行骗村,需配置MRC環(huán)境知識(shí)

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

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

  • allocWithZone方法中加鎖或GCD一次性代碼詳見多線程
    //提供一個(gè)static修飾的全局變量呀枢,強(qiáng)引用著已經(jīng)實(shí)例化的單例對(duì)象實(shí)例
    static id _instance;
    
    //保證永遠(yuǎn)只分配一次存儲(chǔ)空間
    +(instancetype)allocWithZone:(struct _NSZone *)zone
    {
        //使用GCD中的一次性代碼
    //    static dispatch_once_t onceToken;
    //    dispatch_once(&onceToken, ^{
    //        _instance = [[super allocWithZone:zone]init];
    //    });
    
        //使用加鎖的方式胚股,保證只分配一次存儲(chǔ)空間
        @synchronized(self) {
            if (_instance == nil) {
                _instance = [super allocWithZone:zone];
            }
        }
        return _instance;
    }
    
    //類方法,返回一個(gè)單例對(duì)象
    +(instancetype)shareTools
    {
         //注意:這里建議使用self,而不是直接使用類名Tools(考慮繼承)
    
        return [[self alloc]init];
    }
    
    //讓代碼更加的嚴(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;
    }
    
    #if __has_feature(objc_arc)
        //如果是ARC環(huán)境下
    #else
        //如果是MRC環(huán)境下
    //在MRC環(huán)境下裙秋,如果用戶retain了一次琅拌,那么直接返回instance變量,不對(duì)引用計(jì)數(shù)器+1
    //如果用戶release了一次财忽,那么什么都不做倘核,因?yàn)閱卫J皆谡麄€(gè)程序運(yùn)行過程中都擁有且只有一份,程序退出之后被釋放即彪,所以不需要對(duì)引用計(jì)數(shù)器操作
    -(oneway void)release
    {
    }
    
    -(instancetype)retain
    {
        return _instance;
    }
    
    //慣用法紧唱,有經(jīng)驗(yàn)的程序員通過打印retainCount這個(gè)值可以猜到這是一個(gè)單例
    -(NSUInteger)retainCount
    {
        return MAXFLOAT;
    }
    #endif
    

單例封裝宏

01 注意條件編譯的代碼不能包含在宏定義里面
02 宏定義的代碼只需要寫一次就好,之后直接拖到項(xiàng)目中用就OK
  • .h文件
    #define SingleH(name) +(instancetype)share##name;
  • .m文件
    #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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隶校,一起剝皮案震驚了整個(gè)濱河市漏益,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌深胳,老刑警劉巖绰疤,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異舞终,居然都是意外死亡轻庆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門敛劝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來余爆,“玉大人,你說我怎么就攤上這事夸盟《攴剑” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵上陕,是天一觀的道長桩砰。 經(jīng)常有香客問我,道長释簿,這世上最難降的妖魔是什么亚隅? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮庶溶,結(jié)果婚禮上枢步,老公的妹妹穿的比我還像新娘。我一直安慰自己渐尿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布矾瑰。 她就那樣靜靜地躺著砖茸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪殴穴。 梳的紋絲不亂的頭發(fā)上凉夯,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天货葬,我揣著相機(jī)與錄音,去河邊找鬼劲够。 笑死震桶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的征绎。 我是一名探鬼主播蹲姐,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼人柿!你這毒婦竟也來了柴墩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤凫岖,失蹤者是張志新(化名)和其女友劉穎江咳,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哥放,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡歼指,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了甥雕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片踩身。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖犀农,靈堂內(nèi)的尸體忽然破棺而出惰赋,到底是詐尸還是另有隱情,我是刑警寧澤呵哨,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布赁濒,位于F島的核電站,受9級(jí)特大地震影響孟害,放射性物質(zhì)發(fā)生泄漏拒炎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一挨务、第九天 我趴在偏房一處隱蔽的房頂上張望击你。 院中可真熱鬧,春花似錦谎柄、人聲如沸丁侄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸿摇。三九已至,卻和暖如春劈猿,著一層夾襖步出監(jiān)牢的瞬間拙吉,已是汗流浹背潮孽。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留筷黔,地道東北人往史。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像佛舱,于是被迫代替她去往敵國和親椎例。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

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