结论:

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:)这个方法。因此,谜底揭开了,整个离奇的故事真相大白~

转载于:https://www.cnblogs.com/cchHers/p/9397085.html

在项目中谨慎为系统类添加分类!!!!!相关推荐

  1. Android项目中常用的工具类集(史上最全整理)

    如果你是一名有经验的Android开发者,那么你一定积累了不少的工具类,这些工具类是帮助我们快速开发的基础.如果你是新手,那么有了这些辅助类,可以让你的项目做起来更加的简单. 下面介绍一个在GitHu ...

  2. swift5.给系统类添加便利构造函数

    swift5.给系统类添加便利构造函数 便利构造函数是swift的重点. swift并没有分类,所谓分类就是给系统类做扩展. 我们使用便利构造函数去给系统类进行拓展. 我们创建类的对象,直接使用构造函 ...

  3. qt项目中的某一个类的输出中文信息乱码,其它类中文输出正常

    问题描述 qtcreate5.13.2中整个项目中通过添加头文件,使用qDebug()输出中文打印信息,输出中文都是正常的,但是有一个类的输出中文是乱码. 解决方法 修改该类的编码格式.由于项目默认采 ...

  4. android项目中有哪几种依赖关系,Android Studio项目中三种依赖的添加方式

    通常一个AS项目中的依赖关系有三种,一是本地依赖(主要是对本地的jar包),二是模块依赖,三是远程依赖:添加这些依赖的目的在于上我们想要在项目的某一个模块中使用其中的功能,比如okttp这个网络框架库 ...

  5. ios 开发 怎样在项目中使用除系统外的字体

    最近项目中使用到了,需展示银行卡基本信息. 如图 银行卡卡号字体格式并不能用xcode 自带的系统字体来显示,这是我们需要导入外部的字体样式.(银行卡卡号字体:Farrington7B_Qiqi字体) ...

  6. 将一个项目中已有的文档添加到另一个项目中的方法

    我本来是在第一个项目中打开Finder,然后直接拖拽到第二个项目中的. 但发现删除第一个项目,第二个项目中直接找不到那几个拖拽过去的文档了. 所以对于我的情况,也就是从网上搞来的代码,需要打开Find ...

  7. Swift项目中不能定义OC类继承Swift类

    2019独角兽企业重金招聘Python工程师标准>>> 报错原因 Swift项目中 OC文件类  继承  Swift文件类 Cannot subclass a class with ...

  8. iconfont添加新图标_老项目中的iconfont字体图标添加新的图标

    最近,一直在折腾自己的新的博客,采用的是halo博客系统,感觉还是很不错的,就是主题有点少,自用的主题是siren,感觉自己做的不错就分享到了halo论坛,然后被提示标题前面的图标不显示. 也不知道说 ...

  9. java 项目中常用的工具类总结

    1.文件 1.根据图片的链接,下载图片 package com.lingxu.module.BigDataJoinMessage.util;import java.io.FileOutputStrea ...

最新文章

  1. 进一步封装axios并调用其读取数据(吐槽~在安卓9.0以下或者IOS10.X以下手机端H5页面不支持,在这两种情况下的系统只能使用ajax或者原生js请求后台数据)
  2. ASP.NET 2.0实现自带TreeView的客户端连带选择
  3. 如果你对java的异常处理头皮发麻,那就进来吧
  4. 计算机培训开场白,面试开场白及自我介绍范文4篇
  5. Python 类继承,__bases__, __mro__, super
  6. mysql 字符串转long_把数据库中的字符串格式转为long类型
  7. 20150504-日报
  8. 阿里云胡晓明:数据智能将为城市生活带来真正价值
  9. 计算机普通用户禁止修改c盘,保护C盘数据win7中设置禁止修改C盘文件的方法
  10. 随想录(从kaldi学习语音识别)
  11. Node mongoose 结尾总结
  12. 李宏毅机器学习HW1_pm2.5prediction(adagrad/gradient descent/SGD)
  13. ubuntu 双网卡内外网优先级设置
  14. Package Cache搬家
  15. 奇迹之剑萌新晋升大神辅助攻略 奇迹之剑游戏脚本挂机工具介绍
  16. gbox推荐源_GBox
  17. php源码dede,php网站管理系统 DedeCMS v5.7 SP2 UTF8 20180109正式版
  18. 中国剩余定理(c语言)
  19. Prometheus监控以及告警配置
  20. 怎么将几个QQ对话窗口合并和分离

热门文章

  1. C#排队处理DEMO
  2. String类及其构造器和常用方法
  3. 类内的函数共享给对象使用
  4. HDU 1010 Tempter of the Bone DFS(奇偶剪枝优化)
  5. 7个你可能不认识的CSS单位
  6. Using dbms_shared_pool.purge to remove a single task from the library cache
  7. Web攻防之XSS,CSRF,SQL注入
  8. following symbols must have non local/private scope错误问题解决方法
  9. 批量删除某个目录下的 某类型文件方法
  10. cs架构嵌入bs_车牌识别CS架构和BS架构详解