iOS中KVC的底層實現流程

1. KVC的使用

KVC的全稱是Key-Value Coding,也就是鍵值編碼,咱們能夠經過一個key來設置或獲取某個屬性的值。KVC所用到的API以下:bash

// 經過key設置屬性值
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;

// 經過key獲取屬性值
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key; 
複製代碼

咱們看到設置和獲取屬性值的方法都有2個,一個是key一個是keyPath這兩個有什麼區別呢?直接看下面示例吧,咱們先定義以下2個類:ui

// Dog類
#import <Foundation/Foundation.h>
@interface Dog : NSObject

@property (nonatomic , assign) NSInteger age;

@end

// Student類
#import <Foundation/Foundation.h>
#import "Dog.h"

@interface Student : NSObject

@property (nonatomic , strong) NSString *name;
@property (nonatomic , strong) Dog *dog;

@end
複製代碼

若是咱們要設置或獲取Student實例對象的name屬性值,經過keykeyPath方式都是同樣的:編碼

- (void)test{
    self.stu1 = [[Student alloc] init];
    self.stu1.dog = [[Dog alloc] init];
    
    [self.stu1 setValue:@"Jack" forKey:@"name"];
    NSLog(@"經過key的方式--%@",[self.stu1 valueForKey:@"name"]);
    
    [self.stu1 setValue:@"Bob" forKeyPath:@"name"];
    NSLog(@"經過keyPath的方式--%@",[self.stu1 valueForKeyPath:@"name"]);
}
複製代碼

可是若是咱們要設置或獲取Student實例對象的dogage屬性值,那就只能經過keyPath的方式了。此時若是仍是使用key的方式設置屬性值的話就會拋出setValue:forUndefinedKey:的異常。atom

- (void)test{
    self.stu1 = [[Student alloc] init];
    self.stu1.dog = [[Dog alloc] init];
  
    [self.stu1 setValue:@5 forKeyPath:@"dog.age"];
    NSLog(@"%@",[self.stu1 valueForKeyPath:@"dog.age"]);
}
複製代碼

2 KVC設置屬性值的流程

咱們以setValue:forKey:爲例,KVC設置屬性值的整個流程以下圖所示: spa

KVC設置屬性值的流程
好比咱們執行 [self.stu1 setValue:@"Jack" forKey:@"name"];這句代碼,其底層執行流程以下:

  • 首先找到self.stu1isa指向的類對象,在類對象的方法列表中按照setName_setName的順序進行查找(也就是先查找看有沒有setName這個方法,沒有的話再查找有沒有_setName方法)。
  • 前面若是查找到了方法,就調用方法。
  • 前面若是沒有查找到方法,底層就會調用Student類的+ (BOOL)accessInstanceVariablesDirectly;方法。若是返回值是YES就表示容許直接訪問類的成員變量,返回NO表示不容許。這個方法是須要咱們在Student類中重寫的,由開發者來決定是否容許訪問成員變量,若是不重寫,默認是返回YES。
  • 若是上一步返回的是NO,那會直接拋出異常setValue:forUndefinedKey:
  • 若是返回的是YES的話,那就會按照_name_isNamenameisName這樣一個順序來查找類對象中的成員屬性列表,若是找到了就直接賦值;若是沒有找到就拋出異常setValue:forUndefinedKey:

3 KVC獲取屬性值的流程

KVC獲取屬性值的流程圖以下: code

KVC獲取屬性值的流程

好比咱們執行[self.stu1 valueForKey:@"name"];這句代碼,其底層執行流程以下:cdn

  • 首先找到self.stu1的isa指向的類對象,在類對象的方法列表中按照getNamenameisName_name的順序進行查找。
  • 上一步若是查找到了方法,就直接調用方法。
  • 若是沒有找到方法,就會調用Student類的+ (BOOL)accessInstanceVariablesDirectly;方法,看其返回的是YES仍是NO;
  • 若是上一步返回的是NO,就直接拋出異常valueForUndefinedKey:
  • 若是返回的是YES,就會按照_name_isNamenameisName這樣一個順序來查找類對象中的成員屬性列表,若是找到了就直接取值;若是沒有找到就拋出異常valueForUndefinedKey:
相關文章
相關標籤/搜索