美文网首页
KVO与Category

KVO与Category

作者: CoderHG | 来源:发表于2017-12-31 23:58 被阅读237次

    概要

    本文主要介绍的是

    • 1、 @property 语法在不同场景的语义以及注意事项。
    • 2、Category中实现 KVO 监听。

    开门见山来两个疑问:

    KVO是什么?
    Category(分类)又是是什么?

    关于上面的两个问题,只要是做个iOS开发的大神都知道,网上也有一大把的相关文章。那么今天要探讨一个什么问题呢?正如标题,讨论的是KVO与Category,并非其中的一个技术点。接下来,我们慢慢的深入。

    一、@property

    先来回顾一下这个语法,那么问题来了:

    1. @property是干什么的?
    2. @property在什么地方能用到?

    主要强调一下第二个问题:一般用于Class与Category中。那么问题又来了:

    分别在Class 与 Category 中有什么区别?

    终于将这个小专题的主题引出来了。那么赶紧下载我的代码_KVO_Category一起研究研究吧。

    先看看分别在Class与Category中定义了一个属性hgNamecategoryName

    image.png

    首当其冲的什么也不要操作, 分别到KVObject.m与NSObject+KVO.m文件中去逛逛, 发现NSObject+KVO.m中有这样的提示, 然而在KVObject.m中没有。

    image.png

    这到底什么意思?

    具体是什么意思,我也不知道,反正苹果大大就是这么设计的。根据NSObject+KVO.m文件中的提示需要实现两个方法, 仔细一看便知道是categoryName属性的seter与getter方法。如果现在去调用categoryName属性的seter与getter方法是会crach的,因为没有实现。确确的说,现在categoryName属性是没有任何作用的。一般在分类中使用@property语法的话就务必在m文件中实现seter或者getter方法。

    那就按照提示, 我们来处理来重写一下getter方法吧,问题又来了:

    image.png
    没有找到对应的成员变量!!!!!

    好了, 到这里我们已经差不多知道@property分别在 class 与 Category 中有什么区别?

    经典总结: 在Category 中仅仅是对相应属性做了一个getter与setter方法的声明,没有自动生成具体方法的实现与没有自动生成对应的成员变量。换句话来说,在class中都是会自动生成的。

    但是,问题又来了,相对来说这个问题与这个专题没有太大的关联性,但是的的确确的是一个值得关注的问题。在KVObject.m文件中同时重写setter与getter方法, 是这样的:

    image.png

    奇了怪了,尽然提示说没有找到成员变量_hgName!!!!,第一次遇到这种事情真心让人着急,赶紧到处看看是那里出现了问题!!!!最后发现,如果同时重写了setter与getter方法的话, 苹果大大久不在自动生成对应的成员变量了!!!!厉害了,我的锅锅锅。。。。

    决解方法是,我们回归原始方式,自己手动搞一个成员变量, 这样就可以了:


    image.png

    是不是应该点个赞!!!!

    各位大神,我们这次的主题是什么来着,感觉上面说的与主题没有半毛钱的关系。其实关系大着呢!!!!在你上面我们遇到一个问题,在分类中@property属性没有自动生成一个成员变量。接下来,我们就来讨论一下在分类中的成员变量是个什么鬼?

    二、Category中的成员变量

    首当其冲的给分类添加一个成员变量, 结果是这样的:


    image.png

    意思就是,在分类中不能有这个定义,这个结论99.9%的开发者都知道。废话不多说,直接说重点:如果想要在分类中添加成员变量,是不能像class中那么简单的添加, 需要借助runtime机制。这个恐怕只有99%的开发者知道,但是为了说明问题,我还是copy一下代码, 为了主题做铺垫。

    完整代码如下:


    image.png

    验证如下:

    image.png

    到现在为止,给一个分类添加一个成员变量的功能是OK了。与主题貌似还有一点距离。

    三、给Category的成员变量添加KVO监听

    这个样子的:


    image.png

    代码运行起来,结果是非常的GOOD!那么问题又来了:KVO是如何做到监听的?
    网上有这么种说法:执行了setter方法。确实是这样的,如果直接给成员变量赋值是不会触发系统的下面的方法的,网上是这样么说的,我也求证过:

    image.png

    但是,还有一点估计很多大神可能不知道,这个需要在class中求证,在网上也很少有大神提到这一点。就是如果在class中重写了setter方法, 然后不给成员变量赋值, 那么还会出发上面的这个方法么?大家可以先想一下, 代码是这样:

    image.png

    实现了setter方法, 但是没有给成员变量赋值, 在外面调用了setter方法, 那么KVO还有效么?


    思考中...


    思考中...


    思考中...


    思考中...


    思考中...


    思考中...


    思考中...


    思考中...

    我亲测的结果是:这种情况下KVO还是有效的,只是旧值与新值是一样的。厉害了,我的哥。看来这个setter方法还有什么未解之谜。后来又发现了这两个方法:

    image.png

    惊奇的发现,在不调用setter方法的前提下, 我调用这个updateHGName方法,KVO尽然被触发。

    所以在这里我猜想:当执行setter方法可能至少在某个地方也执行了至少以上两个方法。 关于这一点,先不展开讨论,我们知道在某个地方应该是调用了,就可以。关于这个问题,大家靠椅参考这篇经典的文章整理了一下关于KVO的姿势,介绍得挺棒的。

    好的,那么现在我们有换到NSObject+KVO分类中,再添加一个属性,毕竟这篇介绍主要是以Category为主以Class为辅。接下来要实现的功能是:当categoryName改变的同时,extraName也要改变,同时两个都要触发KVO功能。
    通过上面的介绍,具体是代码, 应该就是这样子的:

    image.png

    这样就能实现,在触发categoryName的同时也触发了extraNameKVO

    总结

    到这里也就简单的介绍完了,内容其实不多,都是一些平时开发中不是太注意的细节。主要介绍了一下几点:

    • 1.@property在Class 与Category中的异同
    • 2.Category中如何添加成员变量
    • 3.给Category的成员变量添加KVO监听以及KVO的触发条件调用setter方法或者手动的调用willChangeValueForKey:与didChangeValueForKey:

    问题

    当在监听了一个属性,在你当前Class中重写了这个属性的setter方法, 请问:在被调用这个setter方法的时候, 是否还会触发KVO?

    思考中...


    思考中...


    思考中...


    思考中...


    思考中...


    思考中...


    思考中...


    思考中...


    思考中...

    答案是: 会的

    原因是:
    先看下图:


    image.png

    被KVO监听的对象的isa被动态的指向了一个当前对象的子类对象,每次调用这个setter方法的时候, 其实是县调用其子类的的setter方法。具体看这里:

    image.png

    所以在子类中, 应是重写了setter方法,可能是这样的:

    image.png

    谢谢~

    参考:
    整理了一下关于KVO的姿势

    相关文章

      网友评论

          本文标题:KVO与Category

          本文链接:https://www.haomeiwen.com/subject/srkagxtx.html