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
屬性值,經過key
或keyPath
方式都是同樣的:編碼
- (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
實例對象的dog
的age
屬性值,那就只能經過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"]);
}
複製代碼
咱們以setValue:forKey:
爲例,KVC
設置屬性值的整個流程以下圖所示: spa
[self.stu1 setValue:@"Jack" forKey:@"name"];
這句代碼,其底層執行流程以下:
self.stu1
的isa
指向的類對象,在類對象的方法列表中按照setName
、_setName
的順序進行查找(也就是先查找看有沒有setName
這個方法,沒有的話再查找有沒有_setName
方法)。Student
類的+ (BOOL)accessInstanceVariablesDirectly;
方法。若是返回值是YES
就表示容許直接訪問類的成員變量,返回NO
表示不容許。這個方法是須要咱們在Student
類中重寫的,由開發者來決定是否容許訪問成員變量,若是不重寫,默認是返回YES。NO
,那會直接拋出異常setValue:forUndefinedKey:
。YES
的話,那就會按照_name
、_isName
、name
、isName
這樣一個順序來查找類對象中的成員屬性列表,若是找到了就直接賦值;若是沒有找到就拋出異常setValue:forUndefinedKey:
。KVC
獲取屬性值的流程圖以下: code
好比咱們執行[self.stu1 valueForKey:@"name"];
這句代碼,其底層執行流程以下:cdn
getName
、name
、isName
、_name
的順序進行查找。Student
類的+ (BOOL)accessInstanceVariablesDirectly;
方法,看其返回的是YES仍是NO;NO
,就直接拋出異常valueForUndefinedKey:
。YES
,就會按照_name
、_isName
、name
、isName
這樣一個順序來查找類對象中的成員屬性列表,若是找到了就直接取值;若是沒有找到就拋出異常valueForUndefinedKey:
。