前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >编码篇-继承+通知看方法的实现和delloc方法的调用

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

作者头像
進无尽
发布2018-09-12 18:29:06
7700
发布2018-09-12 18:29:06
举报
文章被收录于专栏:進无尽的文章進无尽的文章

场景

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销毁.

代码语言:javascript
复制
[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依然会被执行很多次。
代码语言:javascript
复制
 #最后一个参数是表示会对哪个发送者对象发出的事件作出响应,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无法被释放的问题,本文详细分析这个问题,旨在希望大家写程序时注意这个问题。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016.12.27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 场景
  • 问题
  • 分析原因
  • dealloc的不被调用的情况。
  • 验证猜想
  • 解决办法
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档