美文网首页
KVC调用规则

KVC调用规则

作者: MrOreo | 来源:发表于2018-07-05 17:13 被阅读0次
每一天
原创文章,转载请注明:转自: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调用规则

    原创文章,转载请注明:转自:Try_Try_Try 背景 关于KVC的使用方法,网络上已有很多文章介绍,这篇文章讲...

  • KVC/KVO原理

    KVC/KVO原理 KVC setValue:forKey原理 调用setValue:forKey:方法,会直接寻...

  • swift kvc 构造函数

    kvc 是oc特有 ,KVC 本质上是在运行时,直接调用程序会崩溃 介绍 kvc 构造函数 kvc构造函数的作用是...

  • KVC、KVO原理

    一、Key-Value Coding: 键值编码 (KVC) 方法调用: KVC主要通过isa-swizzling...

  • iOS开发中的KVC与KVO

    一、KVC KVC(Key Value Coding):键值编码 1.赋值 对一个对象调用setValue:for...

  • KVC

    1.关于KVC setValue: forKey: 的调用顺序 先找两个set方法 2.关于KVC valueF...

  • iOS-KVC/KVO

    一、KVC 通过关键字,访问属性及成员变量。1.kvc当调用setValue:属性值 forKey:@”name“...

  • iOS面试题续

    KVO和KVC: KVC: KVC是键值编码,是一种间接访问对象实例变量的机制,只用该机制不需要调用set或get...

  • KVC&KVO

    KVC(key-value coding) 概要 KVC允许开发者通过名字访问属性,无需调用明确的存取方法,这样开...

  • Swift基础 - KVC/遍历构造方法

    五.KVC构造方法: KVC构造函数,利用运行时的机制,在运行的时候,给对象动态调用setValue forKey...

网友评论

      本文标题:KVC调用规则

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