事件由来
之前项目中有个让用户一边签署协议,一边录制视频上传的功能,当时法务同学要求的是只能直接拍摄上传,不能让用户在相册里直接选取,然后就有了只能拍摄视频上传的第一个版本。而当用户使用之后表示不能从相册中选取很不方便,有时签署协议过程中出了些问题的话又得重新操作一遍。
收到反馈之后,产品也迅速的给出了方案,在原来的的基础上添加一个本地上传的功能,于是我想到了个骚操作。
原本这个拍照按钮调用的是系统的拍摄视频,但我直接给替换成了之前同事写的直接拍摄上传了。
考虑到之前做启动优化, +load
方法如果越多,app冷启动速度就会越慢,我就将搅拌方法放在了 +initialize
中,然后,意想不到的bug发生了。
BUG
测试小姐姐告诉我线上H5调用相机拍照调不起来,app直接卡死,daily调相机则会直接crash。然而native直接调用的话确是可以的。
寻找原因
native调用的是 PhotoSelectorViewControlle
,而H5调用的则是 WebPhotoSelectorViewController
,这两个控制的关系就是 WebPhotoSelectorViewController
继承自 PhotoSelectorViewControlle
。
在 WebPhotoSelectorViewController
的 +initialize
方法中下断点,如果native直接调用的话,改方法只执行了一遍,而H5调用的话 +initialize
却是执行了两遍,why ???
以上两张图的执行结果表示了第一次方法替换是成功了,但第二次就出现问题了,方法变成了第一次已经替换成功之后的方法,然后在之后的方法就造成了死循环。
1 | - (void)swizz_pushImagePickerController { |
那么问题来了,为什么+initialize
执行了两遍?
之前看load与initialize的异同的时候看见过一张图,
如果子类未实现+initialize
方法的话,是会沿用父类的实现的,这也就是为啥+initialize
执行了两遍。
参照官方文档,PhotoSelectorViewControlle
的initialize先执行了一遍,而WebPhotoSelectorViewController
没有实现initialize,则再一次的执行了父类的initialize。如果不想子类调用父类的initialize,则需要和上图中代码款一样操作就行了。