KVC(Key-value coding)鍵值編碼,就是指iOS的開發中,可以允許開發者通過Key名直接訪問對象的屬性,或者給對象的屬性賦值。而不需要調用明確的存取方法。這樣就可以在運行時動態地訪問和修改對象的屬性。而不是在編譯時確定,這也是iOS開發中的黑魔法之一。
賦值過程:
1. 先找相關方法 set<key>: , _set<key>: , setIs<key>: ;
2.若沒有相關方法,則會調用+(BOOL)accessInstanceVariablesDirectly (判斷是否可以直接訪問變量)。
如果:NO, 那麼直接執行KVC 的 setValue:forUndefinedKey方法(系統異常,未定義key)。
如果: YES, 你什麼繼續尋找相關變量 _<key> , _is<key> , <key> , is<key>。
3.若方法或者成員變量都不存在,則執行 setValue:forUndefindKey 方法,(默認拋出異常)。
4 如果賦值對象爲nil , 則會調用setNilValueForKey:, (拋出異常)
取值過程:
1. 先找相關方法 get<key>: , <key>
2.若沒有相關方法,則會調用+(BOOL)accessInstanceVariablesDirectly (判斷是否可以直接訪問變量)。
如果:NO, 那麼直接執行KVC 的 value:forUndefinedKey方法(系統異常,未定義key)。
如果: YES, 你什麼繼續尋找相關變量 _<key> , _is<key> , <key> , is<key>。
3.若方法或者成員變量都不存在,則執行 value:forUndefindKey 方法,(默認拋出異常)。
異常處理:
1. setNilValueForKey: 賦值爲空
2. (set)value:forUndefindKey Key值不存在
正確性驗證:
調用 vaildateValue 返回bool, 工作原理如下:
1. 先找要驗證的類中是否實現了方法-(BOOL)validate<key>:error: (此方法去驗證要要爭的對象的正確性)。
2 如果沒有實現 -(BOOL)validate<key>:error 方法。 系統默認返回YES.
消息傳遞:
NSArray* arr = @[@"Monday", @"Tuesday", @"Wednesday"];
NSArray* lengthArr = [arr valueForKey:@"length"];
NSLog(@"每個元素的長度%@", lengthArr);
NSArray* lowercaseArr = [arr valueForKey:@"lowercaseString"];
NSLog(@"每個元素轉小寫%@", lowercaseArr);
聚合操作符:
@avg、@count、@max、@min、@sum
NSMutableArray* students = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
TZPerson* student = [TZPerson new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"height":@(1.65 + 0.02*arc4random_uniform(6)),
};
[student setValuesForKeysWithDictionary:dict];
[students addObject:student];
}
NSLog(@"%@", [students valueForKey:@"height"]);
/// 平均身高
float avg = [[students valueForKeyPath:@"@avg.height"] floatValue];
NSLog(@"%f", avg);
數組操作符:
去重 /不去重 @distinctUnionOfObjects @unionOfObjects
NSMutableArray* students = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
TZPerson* student = [TZPerson new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"height":@(1.65 + 0.02*arc4random_uniform(6)),
};
[student setValuesForKeysWithDictionary:dict];
[students addObject:student];
}
NSLog(@"%@", [students valueForKey:@"height"]);
NSArray* arr = [students valueForKeyPath:@"@distinctUnionOfObjects.height"];
NSLog(@"arr = %@", arr);
NSArray* arr1 = [students valueForKeyPath:@"@unionOfObjects.height"];
NSLog(@"arr1 = %@", arr1);
嵌套集合(array&set)操作
@distinctUnionOfArrays @unionOfArrays @distinctUnionOfSets(針對set)
NSMutableArray* students = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
TZPerson* student = [TZPerson new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"height":@(1.65 + 0.02*arc4random_uniform(6)),
};
[student setValuesForKeysWithDictionary:dict];
[students addObject:student];
}
NSMutableArray* students1 = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
TZPerson* student = [TZPerson new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"height":@(1.65 + 0.02*arc4random_uniform(6)),
};
[student setValuesForKeysWithDictionary:dict];
[students1 addObject:student];
}
// 嵌套數組
NSArray* nestArr = @[students, students1];
NSArray* arr = [nestArr valueForKeyPath:@"@distinctUnionOfArrays.height"];
NSLog(@" 二維數組合並去重arr = %@", arr);
NSArray* arr1 = [nestArr valueForKeyPath:@"@unionOfArrays.height"];
NSLog(@"二維數組合不去重arr1 = %@", arr1);
集合代理對象 (一對多)
// .h
@interface TZPerson : NSObject
@property (nonatomic, strong) NSString* name;
@property (nonatomic, assign) int age;
@property (nonatomic, strong) NSString* nick;
@property (nonatomic, assign) float height;
@property (nonatomic, assign) NSUInteger count;
@property (nonatomic, strong) NSMutableArray *penArr;
@end
//.m
@implementation TZPerson
- (NSUInteger) countOfBooks {
return self.count;
}
- (id) objectInBooksAtIndex:(NSUInteger)index {
return [NSString stringWithFormat:@"book %lu", index];
}
// 個數
- (NSUInteger) countOfPens {
return [self.penArr count];
}
// 是否包含這個成員對象
- (id) memberOfPens:(id)object {
return [self.penArr containsObject:object] ? object : nil;
}
// 迭代器
- (id) enumeratorOfPens {
return [self.penArr reverseObjectEnumerator];
}
@end
// ViewController
- (void)viewDidLoad {
[super viewDidLoad];
TZPerson* p = [TZPerson new];
p.count = 5;
NSLog(@"books = %@", [p valueForKey:@"books"]);
p.penArr = [NSMutableArray arrayWithObjects:@"pen0", @"pen1", @"pen2", @"pen3", nil];
NSSet* set = [p valueForKey:@"pens"];
NSLog(@"pens = %@", set);
NSEnumerator* enumerator = [set objectEnumerator];
NSString* str = nil;
while (str = [enumerator nextObject]) {
NSLog(@"%@", str);
}
}