編碼篇-繼承+通知看方法的實現(xiàn)和delloc方法的調用


場景

UITableViewCell B繼承自 UITableViewCell A, UITableViewCell A 注冊了名為A的通知,通知綁定的方法為 方法 A;UITableViewCell B 注冊了名為B的通知,通知綁定的方法為 方法 B。

問題

點擊進入UITableViewCell B中后返回,再進入到 UITableViewCell A中,觸發(fā)通知A,此時會崩潰,崩潰在 UITableViewCell B 的方法B中,( 這里說一下,方法B和方法A是一樣的)

分析原因

Paste_Image.png

如圖所示:UITableViewCell A和UITableViewCell B的關系和方法的調用關系大致如此,崩潰的原因是,由于 方法B和方法A是一樣的,UITableViewCell B 繼承與 UITableViewCell A,由于

Paste_Image.png

UITableViewCell B在初始化的時候調用了 UITableViewCell A中的初始化方法,所以由于繼承的機制,實際上 UITableViewCell B注冊了兩個通知:通知A和通知B。由于方法B和方法A是一樣的,所以UITableViewCell B中的通知A調用方法A的時候,實際上就調用了方法B,(當子類的方法列表中有和父類的方法列表中的方法一樣的情況下,會調用子類中的方法,而不調用父類中的方法,也就是重寫),而實際上 UITableViewCell B 中的方法B設計上不是為 通知A服務的,其中調用的一些未知的數(shù)據(jù),所有就出現(xiàn)了崩潰。

有一個問題:為什么從 UITableViewCell B中POP出后,UITableViewCell B沒有被釋放呢?,就是因為UITableViewCell B沒有在頁面被 POP后被釋放掉,才會出現(xiàn)這樣的 Crash,那么為什么沒被釋放呢

dealloc的不被調用的情況。

ARC下,控制器在被pop后移出棧后會被釋放,但有些時候會發(fā)現(xiàn)控制器出棧的時候不會調用dealloc方法,系統(tǒng)可以幫我們釋放該對象,及其包含的對象;但是卻無法釋放不屬于該對象的一些東西,就造成了 對象的dealloc方法不被調用。而且重寫該方法時不能顯式調用[super dealloc],和繼承中先加載父類再加載子類相反,注銷時先注銷子類之后再注銷父類。因為系統(tǒng)會自動幫你調用父類的dealloc方法。

  • 1.通知的觀察者,或KVO的觀察者

由于通知中心是系統(tǒng)的一個單例,你在注冊通知的觀察者時,實際上是在通知中心注冊的,
這時,即使ARC下系統(tǒng)幫我們釋放了對象,但是在通知中心的觀察還是沒有移除,那么當有
該通知時,依然會嘗試調用該對象的接受通知的方法,這可能會導致一些問題.

  • 2.對象強委托

對于其他的對象來把你當做委托 delegate時,并且是 強引用時,即時你自身被釋放,但是引用你的對象依然還在,這時需要在引用你的對象移除該delegate

  • 3.一些其它的資源,類似地圖頁面。C語言寫的一些好內存的類文件,
  • 4.控制器中NSTimer沒有被銷毀

當viewController中存在NSTimer時,需要特別注意,當調用[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES]時,因為 target:self ,也就是引用了當前viewController,導致控制器的引用計數(shù)加1,如果沒有將這個NSTimer 銷毀,它將一直保留該viewController,無法釋放,也就不會調用dealloc方法。所以,需要在viewWillDisappear之前需要把控制器用到的NSTimer銷毀.

[timer invalidate]; // 銷毀
timertimer = nil; // 置nil
  • 5.viewController中block的循環(huán)引用在ARC下,

block會把它里面的所有對象強引用,包括當前控制器self,因此有可能會出現(xiàn)循環(huán)引用的問題。比如viewController中有個block屬性,在block中又強引用了self或者其他成員變量,那么這個viewController與自己的block屬性就形成循環(huán)引用,導致viewController無法釋放。

很顯然,UITableViewCell B不被釋放是因為在初始化的時候注冊的通知沒有移除,也沒有機會移除了,造成的每創(chuàng)建一個UITableViewCell B 都不會被釋放,而是一直在內存中。

驗證猜想

我們修改 方法B 使方法A和 方法B不一樣。在方法A中打印當前類名,然后多次 push進入UITableViewCell B中后再次進入 UITableViewCell A中,觸發(fā)通知A,調用方法A會出現(xiàn)下面的情況:

Paste_Image.png

跟我們猜想的一樣,由于很多不同的UITableViewCell B 被創(chuàng)建,(都注冊了倆通知,由于繼承的關系,雖然UITableViewCell B 中沒有寫 UITableViewCell A的一些方法,但是UITableViewCell B的方法列表中還是會有 那些方法,只是省去了書寫而已,書寫在了父類文件中)而且沒有被銷毀,所以當UITableViewCell A 中的通知A被觸發(fā)時,同樣的 UITableViewCell B 中的通知A 也被觸發(fā),由于UITableViewCell B 中沒有方法A,于是就去執(zhí)行了 父類(UITableViewCell A)中的方法A,于是就出現(xiàn)了 上圖那樣的場景。

解決辦法

  • 單純避免崩潰的話,在UITableViewCell B中第一個 空的方法A 即可,或者把方法B 和 方法A 修改為不同即可。

  • 可是這樣,UITableViewCell A中的方法A依然會被執(zhí)行很多次。

 #最后一個參數(shù)是表示會對哪個發(fā)送者對象發(fā)出的事件作出響應,nil 時表示接受所有發(fā)送者的事件。,
 #所以我們這里把 object:self ,即可只接受自己觸發(fā)的通知,而不會接受到其它 UITableViewCell觸發(fā)的通知了
 #添加之前先移除所有監(jiān)聽,可以解決多次注冊相同監(jiān)聽的問題。
[[NSNotificationCenter defaultCenter]removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(goodtongzhi:) name:@"goodPopAlert" object:self];

  - (void)goodtongzhi :(NSNotification *)sender
  {
   #如果不是自己觸發(fā)的通知就不處理。
    if (![sender.object isEqual:self]) {
        return;
    }
    
    NSDictionary *dataDic = sender.userInfo;
    NSLog(@"你好我是 %@",self.class);
    if ([dataDic[@"index"] integerValue] == self.tag) {
        
        goods =dataDic[@"data"];
        rightTextLablel[0].text = goods.name;
        rightTextLablel[2].text = goods.danwei;
        baozhiqiTexttF.text = goods.baizhiqi;
        rightTextLablel[4].text = goods.baizhiqidanwei;
    }
  }

小結

雖然我們解決了崩潰,也解決了方法的多次調用,看似達到了要求,其實在 UITableViewCell中注冊通知是很不好的方法,這樣會造成很多 UITableViewCell 無法被釋放,一直在內存中,使用 多層次的Block回調,一樣可以達到通知的效果,而且不會造成UITableViewCell無法被釋放的問題,本文詳細分析這個問題,旨在希望大家寫程序時注意這個問題。

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

相關閱讀更多精彩內容

  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,624評論 30 472
  • 1.OC里用到集合類是什么? 基本類型為:NSArray,NSSet以及NSDictionary 可變類型為:NS...
    輕皺眉頭淺憂思閱讀 1,478評論 0 3
  • 37.cocoa內存管理規(guī)則 1)當你使用new,alloc或copy方法創(chuàng)建一個對象時,該對象的保留計數(shù)器值為1...
    如風家的秘密閱讀 955評論 0 4
  • 父類實現(xiàn)深拷貝時,子類如何實現(xiàn)深度拷貝。父類沒有實現(xiàn)深拷貝時,子類如何實現(xiàn)深度拷貝。? 深拷貝同淺拷貝的區(qū)別:淺拷...
    JonesCxy閱讀 1,203評論 1 7
  • 今天看到一篇文章這樣寫道,“不熬夜已經(jīng)成了我們時代最難的自律,能好好睡覺的年輕人都是潛力股。”感覺自己天天晚睡,是...
    哎喲喂Gg閱讀 290評論 0 0

友情鏈接更多精彩內容