前些日子在項(xiàng)目中因?yàn)檎`用了單例而導(dǎo)致了一系列問題。原來在objective-c中的單例并沒有java或者C#那么簡單的實(shí)現(xiàn),這里記錄下;
問題是這樣被發(fā)現(xiàn)的,在對于一個(gè)UIViewController進(jìn)行pop時(shí)并沒有被dealloc,導(dǎo)致了內(nèi)存泄露。問題代碼類似于下面的:
這里的LWNavigationController是一個(gè)頂級的單例。
問題就出在@property (nonatomic, retain) 這里root居然是一個(gè)retain的對象指針,在這里retain一個(gè)static的單例將導(dǎo)致內(nèi)存泄露,MD,這個(gè)bug找的我好久。。。
解決這個(gè)問題其實(shí)很簡單,把retain改為assign就行了,但這樣如果在協(xié)作編程的時(shí)候如果別人不在意這個(gè)是單例直接進(jìn)行常規(guī)操作的話會帶來很大的問題。
繼續(xù),我們來從根本上解決這個(gè)問題。
我們需要重寫一些方法:
在retain和autorelease什么都不做只是返回自己,release的時(shí)候啥都不做,將retainCount設(shè)為UInt的極大值。
其次是關(guān)于線程安全的實(shí)現(xiàn),這些java都有明確的代碼模式:
關(guān)于線程安全的單例,這篇外文 http://www.numbergrinder.com/2008/12/patterns-in-objective-c-singleton-pattern/ 有比較詳細(xì)的解釋。
嗯,這樣就可以實(shí)現(xiàn)線程安全的單例了,當(dāng)然這里也可以用NSLock實(shí)例去實(shí)現(xiàn)。
最后趁機(jī)深入了下單例模式,發(fā)現(xiàn)instance = [[Singleton alloc] init];這樣的語句是有問題的,它不能以其他方式發(fā)起分配內(nèi)存去實(shí)例化對象,可能會造成多個(gè)實(shí)例被創(chuàng)建。(見《pro objective-c design patterns for ios》 )
該書推薦用
傳NULL到allocWithZone其實(shí)等同與alloc默認(rèn)方法,但注意這里是調(diào)用super的alloc;
本類的allocWithZone被改寫為:
同時(shí)深拷貝也直接重載阻止掉多個(gè)實(shí)例的出現(xiàn)。上面的allocWithZone的重載使得這個(gè)單例也能夠直接用alloc或是allocWithZone進(jìn)行初始化,但返回的一如既往是那個(gè)static的實(shí)例。
這樣一個(gè)objective-c的單例模式才算是完整了。。。啦啦啦,每月末一博寫完,睡覺去了。。。
新聞熱點(diǎn)
疑難解答
圖片精選