Extension中属性合成的坑
本文大约1200字,将会介绍访问扩展Extension中属性时遇到unrecognized selector的坑。
!!!原创文章,转载请注明来源: pany.fun
首先关于Extension,推荐一篇SunnyXX的文章,其中较为详细的讲了Extension的原理及一些用法。本次这个坑发现,也是在我们尝试使用Extension进行一些分离工作的时候遇到的。
#坑
我们在Framework的开发过程中,经常会希望一个类的某些东西不要开放出去,这种需求场景往往我们会使用Extension来实现。在这次的实践中,我们遇到了一个 编译通过,在类的外部访问类的Extension中的属性时,出现unrecognized selector,但在类的内部访问时正确 的问题。而这与我们对于Extension的理解是不太相符的。
#还原
为了搞清楚问题所在,我们搭建了一个更简单更干净的Demo工程进行还原与探究。
Step 0 基本搭建
首先我们在工程中创建了一个Woman类,并填了一个Woman+Secret的扩展 。Woman.h中添加了一个name属性(name属性主要作为参照),Woman+Secret.h中我们添加了一个age属性。
Step1 再现错误
我们在viewController中import头文件Woman.h和Woman+Secret.h 并创建一个Woman实例对象Rala。随后我们通过.age尝试获取Rala的年龄,然而失败了🌝,无论赋值或是取值,都失败🌝
Step2 更神奇
随后我们开始怀疑人生,我们尝试在Woman类内部来访问这个age。我们在Woman类内import头文件Woman+Secret.h,然后在init方法中通过.age来访问扩展中的age属性,并将它设置为18岁。一切都完美运行
Step3 懵逼
😑
#爬坑
出现问题以后,我们第一个想到的是Extension的原理 Extension作为匿名分类,是不是不能加属性?虽然这与我们对Extension的理解是明显相悖的…Sunny在文章中提到 Class Extension 在编译期就会将定义的 Ivar、属性、方法等直接合入主类,所以不同于类别,Extension一定是能够添加属性的,而且是在编译期就完成了。
接下来我们想到了属性的原理,属性其实就是帮我们合成了一个Setter和一个Getter,而在我们这次遇到的问题中,正是方法缺失,所以我们怀疑是合成出了问题。随后我们将代码还原到Step1的时候的状态(不要在Woman类中引用Secret扩展),即一个干净的类且仅在viewController中有操作。然后我们利用Runtime的特性,在viewController中打印了Woman的方法列表
ExtensionDemo[31872:7177170] method->.cxx_destruct
ExtensionDemo[31872:7177170] method->name
果然,并没有合成age相关的方法。我们将代码恢复到Step2的状态,并再次打印了方法列表
ExtensionDemo[31930:7186671] method->.cxx_destruct
ExtensionDemo[31930:7186671] method->name
ExtensionDemo[31930:7186671] method->setAge:
ExtensionDemo[31930:7186671] method->age
不出所料,当我们在Woman类内部需要使用age的时候,系统合成了相关的访问方法。
我们不经意间又进行了一步操作,注释掉Woman类内对age的访问和赋值,并再次打印方法列表,这一次居然得到了跟上述log一模一样的结果——合成了age相关的访问方法。而这与上一步的区别仅是Woman类中import了头文件Woman+Secret.h且并无实际使用。
至此,我们得出了结论
当我们使用Extension时,尤其是在Extension作为独立文件的时候,如果Extension添加了属性,并且希望它被合成,则需要在主类中引入Extension的头文件
在Demo中,我们将正确的用法写在了Man中,毕竟男士的年龄是可以访问的(手动滑稽)
思考
Extension中究竟能否添加属性?
当然可以加,但是加了不一定能用,属性合成依赖于在主类中import扩展的头文件(不在内部使用也要import)
能否给系统类添加扩展并添加属性?
当然不能,因为我们没法在系统类的主类中去import一个头文件
关于编译期的逻辑的猜测
编译器会优先处理主类,然后处理主类的import,如果遇到扩展,就将扩展中的 Ivar、属性、方法等直接合入主类,并对属性进行访问方法合成
创作不易,转载请注明来源!pany.fun
本文链接:http://pany.fun/post/Extension中属性合成的坑/