iOS(Category方法“覆盖”填坑实录)

测试:“xx视图不隐藏了,之前还好的呢。”
【iOS(Category方法“覆盖”填坑实录)】我:“这块代码没动过啊。”
此测试非常靠谱,心虚的我赶紧查问题...
首先找到出事代码,在ViewController类的Category A中有段这样的代码(非现场代码):
-(void)hideView:(NSNotification *)notification { self.testView.hidden = YES; }

在收到通知之后将视图隐藏,断点了下确实没走,查看了下通知注册和发送逻辑也没问题。既然在分类中,是不是方法被Category的特性“覆盖”了?
于是,全局搜索 hideView:,果然在此类的另一个Category B中有位同学不知道啥时候加了这样一段代码(为了给ViewController主类瘦身以及功能解耦,给ViewController加了多个Category):
-(void)hideView:(BOOL)hidden { //do something }

Category B hideView: 方法成功将Category A中的“覆盖”了,关于Category的“覆盖”问题,美团技术有篇文章讲的很详细:《深入理解Objective-C:Category》 。修改了方法名后问题确实很快就解决了...
等等,既然这段代码很久没改过了,为什么之前的版本是好的呢?这勾起了我的兴趣。
经过一会的调查,查明了问题原因:
由于公司在推行组件化,工程异常庞大,目前处于模块间解耦的阶段,平时开发的时候使用CocoaPods搭建了私有库进行开发,测试阶段将CocoaPods中的模块代码直接拷贝到主工程中进行打包(为什么不拷贝打包好的静态库?测试阶段,有问题便于debug)。在拷贝代码的过程中Category A和Category B在Compile Sources中顺序发生了变化,Category B跑到了Category A后面(本来Category B在Category A前面),要知道Category中的方法在类的方法列表中的顺序其实是由编译顺序决定的,后面的方法最终会被加到方法列表的前面,最终实现了方法“覆盖”。
其实,Category 的方法“覆盖”问题在大工程中还是比较常见的,常见的是给UIColor,NSString等系统类添加方法后造成了覆盖,在某些工程中有些类甚至出现了4,5个同名方法... 所以,使用Category给类添加方法时一定要注意命名规范。

    推荐阅读