代表月亮私有你

"你問(wèn)我愛(ài)你有多深, 我愛(ài)你有幾分, 我的情不移, 我的愛(ài)不變, 月亮代表我的心",既然月亮代表我的新,是不是說(shuō)明了我的要私有你?哈哈開(kāi)玩笑,我們來(lái)說(shuō)一個(gè)裝逼的東西~

我們?cè)趯?xiě)OC的過(guò)程中經(jīng)常有這么一種情況,就是我們需要寫(xiě)一個(gè)單例的情況。當(dāng)然我們都會(huì)提供一個(gè)類(lèi)方法類(lèi)似于+(instancetype)sharedInstance之類(lèi)的方法,巴特(but)我們的類(lèi)的開(kāi)山鼻祖都是NSObject,而這個(gè)鼻祖竟然提供了- (instancetype)init讓別人來(lái)調(diào)用。這樣寶寶就不開(kāi)心了,寶寶很委屈,可是寶寶不說(shuō),我就是想讓別人調(diào)用我的類(lèi)方法來(lái)獲得單例嘛(嘔吐)

那么我們有沒(méi)有辦法讓init方法私有化呢?或者是讓小伙伴不要去調(diào)用它呢?答案是木有,因?yàn)槲覀冎繭C沒(méi)有私有化父類(lèi)方法的做法,并且OC有非常強(qiáng)大的Runtime機(jī)制,致使我們沒(méi)有辦法私有化init方法。通常這個(gè)時(shí)候都會(huì)有個(gè)但是,要不然還寫(xiě)這篇文章干嘛。

其實(shí)雖然沒(méi)有完全私有init的方法,但是我們可以通過(guò)一些手段來(lái)私有化它,讓我們來(lái)一個(gè)一個(gè)的看看吧。

首先,我們可以用Clang的Attributes中的unavailable來(lái)讓產(chǎn)生一個(gè)編譯錯(cuò)誤。怎么做呢?簡(jiǎn)單的要命,只要添加如下的聲明即可:

- (instancetype)init __attribute__((unavailable("Disabled. Use +sharedInstance instead")));

那么會(huì)產(chǎn)生什么效果呢?

attribute-unavailable.png

個(gè)人比較喜歡第一種,特別是在寫(xiě)一些開(kāi)源的情況下,能在其他小伙伴調(diào)用的時(shí)候就直接給出編譯錯(cuò)誤。而且也能給出有用的信息提示小伙伴調(diào)用其他的方法進(jìn)行替代。

第二種,通過(guò)使用NS_UNAVAILABLE來(lái)聲明,具體使用方法與第一種類(lèi)似:

- (instancetype)init NS_UNAVAILABLE;

效果如下:

NS_UNAVAILABLE.png

而這種方式也是產(chǎn)生了一個(gè)編譯錯(cuò)誤,只是這種方式?jīng)]有辦法給出更加具體的提示信息,而細(xì)心的小伙伴可以發(fā)現(xiàn),第二種方式的提示信息和第一種方式很像,為什么呢?我們來(lái)看看關(guān)于NS_UNAVAILABLE的定義:

#if !defined(NS_UNAVAILABLE)
#define NS_UNAVAILABLE UNAVAILABLE_ATTRIBUTE
#endif

我們可以從名字UNAVAILABLE_ATTRIBUTE看的出來(lái),它應(yīng)該也是用到了__attribute__只是應(yīng)該提示信息是空字符串,應(yīng)該等價(jià)于下面這兩種情況,至少?gòu)恼宫F(xiàn)的形式上來(lái)看應(yīng)該是等價(jià)的。

- (instancetype)init __attribute__((unavailable));
- (instancetype)init __attribute__((unavailable));

第三種是在init方法中調(diào)用doesNotRecognizeSelector來(lái)搞定,也非常簡(jiǎn)單,大概如下

- (instancetype)init {
    [super doesNotRecognizeSelector:_cmd];
    return nil;
}

這種方法則會(huì)在調(diào)用的時(shí)候拋出一個(gè)類(lèi)似于"unrecognized selector"信息的錯(cuò)誤。這種形式其實(shí)沒(méi)有直接指明真正的原因,可能會(huì)讓用戶(hù)丈二和尚摸不著頭腦的趕腳,可能分分鐘給你差評(píng),所以這種方法可能會(huì)被以欺君罪分分鐘被分尸~

第四種則是在init中通過(guò)斷言或者異常的形式來(lái)讓用戶(hù)在運(yùn)行的時(shí)候crash來(lái)提示用戶(hù),這個(gè)點(diǎn)很像第三點(diǎn),但是通過(guò)斷言或者異常我們可以通過(guò)給出相對(duì)應(yīng)的錯(cuò)誤信息提示用戶(hù)來(lái)用其他方式來(lái)替代的方法,代碼可以如下:

// 通過(guò)斷言
- (instancetype)init {
    NSAssert(false,@"unavailable, use sharedInstance instead");
    return nil;
}

// 或者通過(guò)異常
- (instancetype)init {
    [NSException raise:NSGenericException
                format:@"Disabled. Use +[%@ %@] instead",
     NSStringFromClass([self class]),
     NSStringFromSelector(@selector(sharedInstance))];
    return nil;
}

這種方式雖然能提示正確的信息,可是用戶(hù)必須要到運(yùn)行的時(shí)候才能看到錯(cuò)誤的信息,所以個(gè)人感覺(jué)還是偏遲了一點(diǎn)。

小小的總結(jié)一下,雖然提供了四種方式,但是本來(lái)還是喜歡第一種方式,畢竟第一種方式能在編譯的過(guò)程中就能獲得有用的信息,讓其他的小伙伴即使使用正確的方式。好啦,就醬紫啦,小伙伴可以自己去動(dòng)手嘗試一下了~

PS:具體代碼可以從Github上獲取。

如有問(wèn)題或糾正, 可以聯(lián)系@叫什么都不如叫Pluto-Y或在Github

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容