编码篇-继承+通知看方法的实现和delloc方法的调用


场景

UITableViewCell B继承自 UITableViewCell A, UITableViewCell A 注册了名为A的通知,通知绑定的方法为 方法 A;UITableViewCell B 注册了名为B的通知,通知绑定的方法为 方法 B。

问题

点击进入UITableViewCell B中后返回,再进入到 UITableViewCell A中,触发通知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服务的,其中调用的一些未知的数据,所有就出现了崩溃。

有一个问题:为什么从 UITableViewCell B中POP出后,UITableViewCell B没有被释放呢?,就是因为UITableViewCell B没有在页面被 POP后被释放掉,才会出现这样的 Crash,那么为什么没被释放呢

dealloc的不被调用的情况。

ARC下,控制器在被pop后移出栈后会被释放,但有些时候会发现控制器出栈的时候不会调用dealloc方法,系统可以帮我们释放该对象,及其包含的对象;但是却无法释放不属于该对象的一些东西,就造成了 对象的dealloc方法不被调用。而且重写该方法时不能显式调用[super dealloc],和继承中先加载父类再加载子类相反,注销时先注销子类之后再注销父类。因为系统会自动帮你调用父类的dealloc方法。

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

由于通知中心是系统的一个单例,你在注册通知的观察者时,实际上是在通知中心注册的,
这时,即使ARC下系统帮我们释放了对象,但是在通知中心的观察还是没有移除,那么当有
该通知时,依然会尝试调用该对象的接受通知的方法,这可能会导致一些问题.

  • 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,导致控制器的引用计数加1,如果没有将这个NSTimer 销毁,它将一直保留该viewController,无法释放,也就不会调用dealloc方法。所以,需要在viewWillDisappear之前需要把控制器用到的NSTimer销毁.

[timer invalidate]; // 销毁
timertimer = nil; // 置nil
  • 5.viewController中block的循环引用在ARC下,

block会把它里面的所有对象强引用,包括当前控制器self,因此有可能会出现循环引用的问题。比如viewController中有个block属性,在block中又强引用了self或者其他成员变量,那么这个viewController与自己的block属性就形成循环引用,导致viewController无法释放。

很显然,UITableViewCell B不被释放是因为在初始化的时候注册的通知没有移除,也没有机会移除了,造成的每创建一个UITableViewCell B 都不会被释放,而是一直在内存中。

验证猜想

我们修改 方法B 使方法A和 方法B不一样。在方法A中打印当前类名,然后多次 push进入UITableViewCell B中后再次进入 UITableViewCell A中,触发通知A,调用方法A会出现下面的情况:

Paste_Image.png

跟我们猜想的一样,由于很多不同的UITableViewCell B 被创建,(都注册了俩通知,由于继承的关系,虽然UITableViewCell B 中没有写 UITableViewCell A的一些方法,但是UITableViewCell B的方法列表中还是会有 那些方法,只是省去了书写而已,书写在了父类文件中)而且没有被销毁,所以当UITableViewCell A 中的通知A被触发时,同样的 UITableViewCell B 中的通知A 也被触发,由于UITableViewCell B 中没有方法A,于是就去执行了 父类(UITableViewCell A)中的方法A,于是就出现了 上图那样的场景。

解决办法

  • 单纯避免崩溃的话,在UITableViewCell B中第一个 空的方法A 即可,或者把方法B 和 方法A 修改为不同即可。

  • 可是这样,UITableViewCell A中的方法A依然会被执行很多次。

 #最后一个参数是表示会对哪个发送者对象发出的事件作出响应,nil 时表示接受所有发送者的事件。,
 #所以我们这里把 object:self ,即可只接受自己触发的通知,而不会接受到其它 UITableViewCell触发的通知了
 #添加之前先移除所有监听,可以解决多次注册相同监听的问题。
[[NSNotificationCenter defaultCenter]removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(goodtongzhi:) name:@"goodPopAlert" object:self];

  - (void)goodtongzhi :(NSNotification *)sender
  {
   #如果不是自己触发的通知就不处理。
    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无法被释放的问题,本文详细分析这个问题,旨在希望大家写程序时注意这个问题。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,121评论 29 470
  • 1.OC里用到集合类是什么? 基本类型为:NSArray,NSSet以及NSDictionary 可变类型为:NS...
    轻皱眉头浅忧思阅读 1,359评论 0 3
  • 37.cocoa内存管理规则 1)当你使用new,alloc或copy方法创建一个对象时,该对象的保留计数器值为1...
    如风家的秘密阅读 829评论 0 4
  • 父类实现深拷贝时,子类如何实现深度拷贝。父类没有实现深拷贝时,子类如何实现深度拷贝。• 深拷贝同浅拷贝的区别:浅拷...
    JonesCxy阅读 991评论 1 7
  • 今天看到一篇文章这样写道,“不熬夜已经成了我们时代最难的自律,能好好睡觉的年轻人都是潜力股。”感觉自己天天晚睡,是...
    哎哟喂Gg阅读 242评论 0 0