KVC调用规则

每一天
原创文章,转载请注明:转自:Try_Try_Try

背景

关于KVC的使用方法,网络上已有很多文章介绍,这篇文章讲解的也很全面(https://www.jianshu.com/p/45cbd324ea65)。最近被问到了很多的问题,因此会将问到的问题都总结一下,方便之后查看。

很简单的一句话,描述一下kvc的get方法调用顺序?

嗯哼,我伙呆,当时就火大。

吐槽一下:感觉记住这个顺序用处不太大,可能当时记住了,之后就又忘了。我其实是比较反感问一些需要死记硬背,但是平时用处不太大的问题。如果当时有电脑,我直接可以进行演示操作,验证推倒。我直接说了句:忘了(对面坐的神 笑了一下,我内心开始不淡定,摸了摸后脑勺和鼻子,低下了头。)


目录结构:

    1. 代码结构简介
    • 1.1 类结构
    • 1.2 代码展示
    1. KVC中get调用顺序
    • 2.1 观察图片总结结论
    • 2.2 验证
    1. KVC中set调用顺序

正文:

因为我们对于图片都是敏感的,所以文章中尽量给出图片方便记忆(就像我开头放的那张小魔仙的图片一样,现在你一定还记得---内心笑一下吧)。

1. 代码结构简介

1.1 类结构
类结构
1.2 代码展示

其中Animate.h 和 Plant.h 的 实例变量是一样的。
Animate.h

#import <Foundation/Foundation.h>

// 记录get
@interface Animate : NSObject{
    
//    @public
//    NSString *_age;
//    NSString *_isAge;
//    NSString *age;
//    NSString *isAge;
}

@end

Animate.m

#import "Animate.h"

@implementation Animate


+ (BOOL)accessInstanceVariablesDirectly
{
    return YES;
}

- (NSString *)getAge
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return @"1";
}

- (NSString *)age
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return @"2";
}

- (NSString *)isAge
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return @"3";
}

- (NSString *)_getAge
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return @"4";
}

- (NSString *)_age
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return @"5";
}

@end

Plant.h

#import <Foundation/Foundation.h>

// 记录set
@interface Plant : NSObject{
    
//        @public
//        NSString *_age;
//        NSString *_isAge;
//        NSString *age;
//        NSString *isAge;
}

@end

Plant.m

#import "Plant.h"

@implementation Plant

- (void)setAge:(NSString *)age
{
    NSLog(@"%@--%@", NSStringFromSelector(_cmd), age);
}

- (void)_setAge:(NSString *)age
{
    NSLog(@"%@--%@", NSStringFromSelector(_cmd), age);
}

@end

2. KVC中get调用顺序

好吧,先来一张图,说明执行的顺序,接着验证

2.1 观察图片总结结论
图片
图2.1 getValueForkey:

从上图2.1中可以看出基本的调用顺序,关于为什么是这个流程,其实通过断点验证出来的,并没有从源代码中发现其具体实现过程(关于这点,我一直在查找资料,毕竟要见到本质才相信)。

  • 右边的方法,左边的字段;(先调用方法,再执行字段)
  • 方法调用顺序:getKey、key、isKey、_getKey、_key
  • 字段调用顺序:_key、_isKey、key、isKey
2.2 验证

查看文件Animate相关内容
main.m中添加如下内容

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        // get
        Animate *animate = [[Animate alloc] init];
        animate->_age = @"1";
        animate->_isAge = @"2";
        animate->age = @"3";
        animate->isAge = @"4";

        NSString *age = [animate valueForKey:@"age"];

        NSLog(@"Hello World!");
    }
    return 0;
}
  • 如果将Animate.h和Animate.m中的注释都放开。在NSLog(@"Hello World!");该行打印断点,可以验证出来先执行方法,再执行属性;
  • 验证方法的顺序:先把.h中字段注释,main.m中的字段赋值也进行注释,只留下Animate.m中的几个方法如下:
- (NSString *)getAge
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return @"1";
}

- (NSString *)age
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return @"2";
}

- (NSString *)isAge
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return @"3";
}

- (NSString *)_getAge
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return @"4";
}

- (NSString *)_age
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return @"5";
}

+ (BOOL)accessInstanceVariablesDirectly
{
    return YES;
}

运行后,发现只打印getAge, 接着注释getAge方法,发现打印的其他方法。依次重复几次,就能得出一个顺序:getKey、key、isKey、_getKey、_key

  • 验证公有字段的执行顺序:通过断点查看给哪个字段进行了赋值。然后注释该字段,依次操作,就可得到执行的顺序:_key、_isKey、key、isKey
  • accessInstanceVariablesDirectly方法默认是返回YES,从方法名称也可以看出来该方法的含义,它用来控制实例变量是否可以访问。

3. KVC中set调用顺序

同样再来一张图,说明执行的顺序,接着验证


图3.1 setValue:forKey:

从图3.1中可以发现和图2.1中左边的实例变量的调用顺序是一样的。只是方法调用少了几个。

结论
  • 右边的方法,左边的字段;(先执行方法,再执行字段)
  • 方法调用顺序:setKey、_setKey
  • 字段调用顺序:_key、_isKey、key、isKey
验证

查看文件Plant相关内容
main.m中有如下内容:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
       
        // set
        Plant *plant = [[Plant alloc] init];
        [plant setValue:@"2" forKey:@"age"];
        
        NSLog(@"Hello World!");
    }
    return 0;
}
  • 验证的方法和上述get的操作类似,就会得出上图的结果。这里请自行验证。
    其中Plant.m中的方法如下:
- (void)setAge:(NSString *)age
{
    NSLog(@"%@--%@", NSStringFromSelector(_cmd), age);
}

- (void)_setAge:(NSString *)age
{
    NSLog(@"%@--%@", NSStringFromSelector(_cmd), age);
}

通过验证,就会和图3.1总结的一样。
关于更高深的其他操作这里不再做分析,只对其基本原理进行剖析。


  • 本文相关的demo已放置github.
  • 在阅读中,如果发现文章有不合理的地方,欢迎提出疑问至邮箱:B12050217@163.com.
  • 原创文章,转载请注明:转自:Try_Try_Try
  • OK, game over.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • KVC KVC定义 KVC(Key-value coding)键值编码,就是指iOS的开发中,可以允许开发者通过K...
    暮年古稀ZC阅读 2,201评论 2 9
  • KVC(Key-valuecoding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iOS...
    榕樹頭阅读 733评论 0 2
  • 该文章属于刘小壮原创,转载请注明:刘小壮[https://www.jianshu.com/u/2de707c93d...
    刘小壮阅读 21,150评论 29 115
  • KVC(Key-value coding)键值编码,单看这个名字可能不太好理解。其实翻译一下就很简单了,就是指iO...
    我的梦工厂阅读 905评论 1 8
  • “一定有什么东西是你热爱并且最喜欢去做的,一个未完成的梦想?” “驯服黑夜” ...
    陈如意的幸福生活呀阅读 314评论 0 1