一、僵尸對(duì)象問(wèn)題
在MRC環(huán)境下,我們經(jīng)常會(huì)碰到message sent to deallocated instance 的錯(cuò)誤,這個(gè)錯(cuò)誤的名稱為 EXC_BAD_ACCESS , 多發(fā)生在對(duì)一個(gè)對(duì)象重復(fù)release 而過(guò)度釋放的情況下,也就是所謂的僵尸對(duì)象(NSZombie Object),有時(shí)候也稱作野指針問(wèn)題(指針指向的是僵尸對(duì)象)。自從ios 5.0推出以后,大多數(shù)程序都切換到了ARC環(huán)境,這一類的錯(cuò)誤也少了很多。但是他們并沒(méi)有完全消失,仍然存在于代碼中。下面舉出幾個(gè)常見(jiàn)的例子:
?1. ?委托對(duì)象未置空,常見(jiàn)的如UITableView,UIWebView。
? ? ?這一類控件的委托是異步執(zhí)行的,而且由于年代久遠(yuǎn),他們的delegate 屬性還是assign,而不是現(xiàn)在常用的weak。這就存在一個(gè)問(wèn)題,如果頁(yè)面正在加載數(shù)據(jù),其委托對(duì)象為self , 這時(shí)候頁(yè)面突然退出,委托指向的VC被釋放,而tableView或者webView的delegate沒(méi)有置空,就有可能觸發(fā)僵尸對(duì)象問(wèn)題。正確的解決方法是在頁(yè)面dealloc或者viewWillDisappear的時(shí)候?qū)elegate及時(shí)置空。
2. 注冊(cè)通知后沒(méi)有在dealloc中反注冊(cè)。
? ? ?這個(gè)情況多發(fā)生于VC中,init或viewDidload時(shí)注冊(cè)了通知監(jiān)聽(tīng),但在dealloc時(shí)沒(méi)有反注冊(cè),導(dǎo)致VC釋放以后通知中心仍然保持著對(duì)VC的引用,也就形成了僵尸對(duì)象,當(dāng)相關(guān)通知發(fā)出時(shí),就會(huì)因?yàn)橐爸羔樁罎?。解決方法是在dealloc 時(shí)反注冊(cè)通知監(jiān)聽(tīng)。
二、循環(huán)引用問(wèn)題
1. 委托使用了strong屬性,導(dǎo)致委托對(duì)象和被委托的對(duì)象之間形成循環(huán)引用。
2. block中引用了self,而self沒(méi)有使用weak屬性修飾。由于眾所周知的原因,block會(huì)對(duì)他里面的對(duì)象強(qiáng)引用,而被他引用的對(duì)象如果又持有這個(gè)block,就會(huì)形成循環(huán)引用。
3. 定時(shí)器。由于定時(shí)器在創(chuàng)建時(shí)會(huì)對(duì)指定的target強(qiáng)引用,如果target恰好又是定時(shí)器的持有者時(shí),就形成了循環(huán)引用。
4. JavascriptCore的循環(huán)引用。
? ?如果你的代碼中有對(duì)象(我們暫命名為JSListener)持有了 JSContext,同時(shí)該對(duì)象又實(shí)現(xiàn)了JSExport協(xié)議,那么就很有可能形成JSContext與JSListener的循環(huán)引用。