码迷,mobileinhere.cn
首页 > 其他好文 > 详细

在项目中谨慎为系统类添加分类!!!!!

时间:2018-07-31 19:36:44      阅读:10      评论:0      收藏:0      [点我收藏+]

标签:出现   输出   关于   方式   授权   配置   没有   button   change   

结论:

1、坚决杜绝为系统类做方法交换(见到【class_replacemethod】格杀勿论!)

2、为系统类添加分类时候,属性和方法名必须加上【世上独一无二】的前缀,避免冲突和混淆。


 

之所以让我对上述行为恨之入骨是因为,今天为了一个bug,我花了将近半天时间苦苦追寻原因。

我只是使用了一个简简单单的uiimagepickercontroller的拍照的功能界面,奇葩的现象是,点击快门按钮时---可以看见界面中的按钮发生了视觉上的响应,但是却没有功能上的响应(按道理,我这边按下按钮的时候,拍照就会完成输出图片数据)。

我的整个思考过程是这样的:

点击没功能反应?难道有谁把这个类中的响应方法重写了?

---寻找uiimagepickercontroller在整个项目中的出现,看有没有对它做分类,或者是子类化。结果是没有的!

那是不是关于uiimagepickercontroller这个类,随着ios的sdk的更新,我有些属性或者方法需要适配下?

---我用ios10.2和ios11.2和最新的ios11.4都看了一遍,都有这个问题。难道从ios10开始就要有些跟之前不一样的适配需要做?我翻看相关的适配博客,没有发现!

难道是我对事件响应链做了一些调整?导致事件被阻断?

---我回头看了一眼uiimagepickercontroller对象创建后使用的是模态出来的,一个简单的展示链,没有问题!

难道多线程问题?

---nonono!我核对了下代码,整个过程都在主线程中,至于就算uiimagepickercontroller里面的处理上开了子线程,那也不归我们管,它暴露出来的api肯定是在主线程的。

那就见鬼了~但是,不对啊,就这个简单的uiimagepickercontroller,不至于啊!

---我应该是知道肯定是项目中的其他sdk的环境影响到了它,但是会是什么呢?为了更加确定我的这个想法,给自己继续追寻原因的信心,我新建demo,这块代码原样放入。卧槽,完美运行。

那行,我这样的话,我要一查到底!

---能够引起这个问题的全局原因,那么就是项目的配置数据有误,那么就是分类的原因。

  项目的配置数据就是那些,最多就是在info文件中说明下使用相机的原因,方便获取用户的授权。因此我肯定,这块没有问题。

  分类的话,我已经确定了没有uiimagepickercontroller的分类。那么肯定就是其他系统类的分类了。

  首先,添加分类的不可控性体现在:

(1)如果在分类中重写类的方法,分类的重写优先级是最高的。  

(2)如果系统对uiimagepickercontroller添加了一些分类(包括不暴露在api中的),刚好又与项目中对其的分类方法名重复,会后入为主的。

(3)另外分类是会在编译器就全部加上的,如果在分类中对类本身做的处理是会影响到类本身的。也就是说,如果对类中的方法做了方法转移的处理,那就无形中影响了。

于是我赶紧搜索方法转移的class_replacemethod方法名有没有在项目中出现。果然,项目中对uibutton的分类中重写了+load类方法,在改方法中做了方法转移!

正如前面分析的,重写+load方法的优先级:分类中>子类中>类本身。

并且重写的是+load这个方法,完全可以做到悄无声息。

为了进一步验证就是这个原因,我直接将这个分类的实现方法注释掉,然后运行项目~【method_exchangeimplementations完美运作!!】


刚刚时候的是相当于反编译的方式把问题的根源找到了,现在我需要的是使用顺推的方法,把问题的出现原因梳理清楚。

通过查看uibutton的这个分类知道,它是将@selector(sendaction:to:forevent:)这个方法替换掉了。sendaction:to:forevent:方法中实际调用的是objc_setassociatedobject,替换后的方法,在其中加了一个计时器,使得规定时间内,只能objc_setassociatedobject调用一次。

这样的做法,应该是为了防止button高频按动而做的改动。

然而,uiimagepickercontroller功能界面中的快门按钮,实际上是在拍照功能时,按住快门键不放,可以实现高频连拍的功能(我试了下最多时999张),这样的话,就很好解释通了。虽然,按住快门键按钮不放是一个“长按”手势,但是其内部的实现肯定是高频的调用@selector(sendaction:to:forevent:)这个方法。说到这里,我得说明下,虽然长按手势和单点手势表面上的确是不一样的,但是其内部都调用了@selector(sendaction:to:forevent:)这个方法。因此,之前写button这个分类的目的虽然是防止用户高频的单击按钮,但是现在用户虽然不是高频的单击,而是长按,但是都调用的是@selector(sendaction:to:forevent:)这个方法。毕竟,当初为了防止用户高频单击,是替换掉了@selector(sendaction:to:forevent:)这个方法。因此,谜底揭开了,整个离奇的故事真相大白~

在项目中谨慎为系统类添加分类!!!!!

标签:出现   输出   关于   方式   授权   配置   没有   button   change   

原文地址:www.cnblogs.com/cchhers/p/9397085.html

(0)
(0)
   
举报
评论 一句话评论(0
0条  
登录后才能评论!
2014 mobileinhere.cn 版权所有 京icp备13008772号-2
华人娱乐注册