概要
本文主要介绍的是
- 1、 @property 语法在不同场景的语义以及注意事项。
- 2、Category中实现 KVO 监听。
开门见山来两个疑问:
KVO是什么?
Category(分类)又是是什么?
关于上面的两个问题,只要是做个iOS开发的大神都知道,网上也有一大把的相关文章。那么今天要探讨一个什么问题呢?正如标题,讨论的是KVO与Category,并非其中的一个技术点。接下来,我们慢慢的深入。
一、@property
先来回顾一下这个语法,那么问题来了:
1. @property是干什么的?
2. @property在什么地方能用到?
主要强调一下第二个问题:一般用于Class与Category中。那么问题又来了:
分别在Class 与 Category 中有什么区别?
终于将这个小专题的主题引出来了。那么赶紧下载我的代码_KVO_Category一起研究研究吧。
先看看分别在Class与Category中定义了一个属性hgName与categoryName。
首当其冲的什么也不要操作, 分别到KVObject.m与NSObject+KVO.m文件中去逛逛, 发现NSObject+KVO.m中有这样的提示, 然而在KVObject.m中没有。
这到底什么意思?
具体是什么意思,我也不知道,反正苹果大大就是这么设计的。根据NSObject+KVO.m文件中的提示需要实现两个方法, 仔细一看便知道是categoryName属性的seter与getter方法。如果现在去调用categoryName属性的seter与getter方法是会crach的,因为没有实现。确确的说,现在categoryName属性是没有任何作用的。一般在分类中使用@property语法的话就务必在m文件中实现seter或者getter方法。
那就按照提示, 我们来处理来重写一下getter方法吧,问题又来了:
没有找到对应的成员变量!!!!!
好了, 到这里我们已经差不多知道@property分别在 class 与 Category 中有什么区别?
经典总结: 在Category 中仅仅是对相应属性做了一个getter与setter方法的声明,没有自动生成具体方法的实现与没有自动生成对应的成员变量。换句话来说,在class中都是会自动生成的。
但是,问题又来了,相对来说这个问题与这个专题没有太大的关联性,但是的的确确的是一个值得关注的问题。在KVObject.m文件中同时重写setter与getter方法, 是这样的:
奇了怪了,尽然提示说没有找到成员变量_hgName!!!!,第一次遇到这种事情真心让人着急,赶紧到处看看是那里出现了问题!!!!最后发现,如果同时重写了setter与getter方法的话, 苹果大大久不在自动生成对应的成员变量了!!!!厉害了,我的锅锅锅。。。。
决解方法是,我们回归原始方式,自己手动搞一个成员变量, 这样就可以了:
image.png
是不是应该点个赞!!!!
各位大神,我们这次的主题是什么来着,感觉上面说的与主题没有半毛钱的关系。其实关系大着呢!!!!在你上面我们遇到一个问题,在分类中@property属性没有自动生成一个成员变量。接下来,我们就来讨论一下在分类中的成员变量是个什么鬼?
二、Category中的成员变量
首当其冲的给分类添加一个成员变量, 结果是这样的:
image.png
意思就是,在分类中不能有这个定义,这个结论99.9%的开发者都知道。废话不多说,直接说重点:如果想要在分类中添加成员变量,是不能像class中那么简单的添加, 需要借助runtime机制。这个恐怕只有99%的开发者知道,但是为了说明问题,我还是copy一下代码, 为了主题做铺垫。
完整代码如下:
image.png
验证如下:
到现在为止,给一个分类添加一个成员变量的功能是OK了。与主题貌似还有一点距离。
三、给Category的成员变量添加KVO监听
这个样子的:
image.png
代码运行起来,结果是非常的GOOD!那么问题又来了:KVO是如何做到监听的?
网上有这么种说法:执行了setter方法。确实是这样的,如果直接给成员变量赋值是不会触发系统的下面的方法的,网上是这样么说的,我也求证过:
但是,还有一点估计很多大神可能不知道,这个需要在class中求证,在网上也很少有大神提到这一点。就是如果在class中重写了setter方法, 然后不给成员变量赋值, 那么还会出发上面的这个方法么?大家可以先想一下, 代码是这样:
实现了setter方法, 但是没有给成员变量赋值, 在外面调用了setter方法, 那么KVO还有效么?
思考中...
思考中...
思考中...
思考中...
思考中...
思考中...
思考中...
思考中...
我亲测的结果是:这种情况下KVO还是有效的,只是旧值与新值是一样的。厉害了,我的哥。看来这个setter方法还有什么未解之谜。后来又发现了这两个方法:
惊奇的发现,在不调用setter方法的前提下, 我调用这个updateHGName方法,KVO尽然被触发。
所以在这里我猜想:当执行setter方法可能至少在某个地方也执行了至少以上两个方法。 关于这一点,先不展开讨论,我们知道在某个地方应该是调用了,就可以。关于这个问题,大家靠椅参考这篇经典的文章整理了一下关于KVO的姿势,介绍得挺棒的。
好的,那么现在我们有换到NSObject+KVO分类中,再添加一个属性,毕竟这篇介绍主要是以Category为主以Class为辅。接下来要实现的功能是:当categoryName改变的同时,extraName也要改变,同时两个都要触发KVO功能。
通过上面的介绍,具体是代码, 应该就是这样子的:
这样就能实现,在触发categoryName的同时也触发了extraName的KVO。
总结
到这里也就简单的介绍完了,内容其实不多,都是一些平时开发中不是太注意的细节。主要介绍了一下几点:
- 1.@property在Class 与Category中的异同
- 2.Category中如何添加成员变量
- 3.给Category的成员变量添加KVO监听以及KVO的触发条件调用setter方法或者手动的调用willChangeValueForKey:与didChangeValueForKey:
问题
当在监听了一个属性,在你当前Class中重写了这个属性的setter方法, 请问:在被调用这个setter方法的时候, 是否还会触发KVO?
思考中...
思考中...
思考中...
思考中...
思考中...
思考中...
思考中...
思考中...
思考中...
答案是: 会的。
原因是:
先看下图:
image.png
被KVO监听的对象的isa被动态的指向了一个当前对象的子类对象,每次调用这个setter方法的时候, 其实是县调用其子类的的setter方法。具体看这里:
所以在子类中, 应是重写了setter方法,可能是这样的:
谢谢~
参考:
整理了一下关于KVO的姿势
网友评论