KVC(key-value coding),鍵值編碼。指在iOS開發中,開發者可以通過屬性名直接訪問屬性,給屬性賦值或者取值,而不需要顯式的調用setter和getter方法,這樣就可以在運行時動態的訪問和修改對象的屬性。
KVC常用的四個方法
- (nullable id)valueForKey:(NSString *)key; //直接通過Key來取值
- (void)setValue:(nullable id)value forKey:(NSString *)key; //通過Key來設值
- (nullable id)valueForKeyPath:(NSString *)keyPath; //通過KeyPath來取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; //通過KeyPath來設值
valueForKey 和 setValue: forKey:的簡單用法
我們都知道當一個對象的屬性在聲明文件(.h)中聲明時,是可以用點語法訪問并賦值的,但是如果聲明在實現文件(.m)中,在外面用點語法是訪問不到的,此時KVC就起到作用了
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface Book : NSObject
@end
#import "Book.h"
@interface Book()
@property (strong, nonatomic) NSString *name;
@property (assign, nonatomic) CGFloat price;
@end
@implementation Book
@end
//在控制器中實現下面代碼
Book *book1 = [[Book alloc]init];
[book1 setValue:@"ios" forKey:@"name"];
[book1 setValue:@12 forKey:@"price"];
NSString *name = [book1 valueForKey:@"name"];
NSNumber *price = [book1 valueForKey:@"price"];
NSLog(@"name = %@,price = %@",name,price.floatValue);
//打印結果如下
name = ios,price = 12.000000
這樣以后我們自定義一些控件的時候訪問私有屬性就方便多了。 另外,我們還可以修改系統控件的內部屬性,如我們自定義好一個tabbar,可以用下面的方式替換系統本來的UITabbar
[self setValue:[[CustomTabbar alloc]init] forKey:@"tabBar"];
valueForKeypath 和 setValue:forKeypath: 的簡單用法
當一個對象成為另一個對象的屬性時,使用KVC就方便的多
#import <Foundation/Foundation.h>
@class Address;
@interface People : NSObject
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) Address *address;
@property (assign, nonatomic) NSInteger age;
@end
@interface Address : NSObject
@property (strong, nonatomic) NSString *contry;
@end
#import "People.h"
@interface People ()
@end
@implementation People
@end
@interface Address ()
@end
@implementation Address
@end
//在控制器中實現下面代碼
Address *address = [[Address alloc]init];
address.contry = @"China";
People *people = [[People alloc]init];
people.address = address;
NSString *country1 = people.address.contry;
NSString *country2 = [people valueForKeyPath:@"address.contry"];
NSLog(@"1 = %@ 2 = %@",country1,country2);
[people setValue:@"中國" forKeyPath:@"address.contry"];
country1 = people.address.contry;
country2 = [people valueForKeyPath:@"address.contry"]; NSLog(@"1 = %@ 2 = %@",country1,country2);
KVC對于keyPath是搜索機制第一步就是分離key,用小數點.來分割key,然后再像普通key一樣按照順序搜索下去。
KVC 和 字典
常用的兩個方法
- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;
Addresss *add = [[Addresss alloc]init];
add.country = @"China";
add.province = @"Hebei";
add.city = @"Qinhuangdao";
add.district = @"Yanghedao";
NSArray *keys = @[@"country",@"province",@"city",@"district"];
//把對應key所有的屬性全部取出來
NSDictionary *dict = [add dictionaryWithValuesForKeys:keys];
NSLog(@"dict = %@",dict);
//字典轉模型
NSDictionary *modiDic = @{@"country":@"中國",@"province":@"河北省",@"city":@"秦皇島市",@"district":@"洋河道"};
[add setValuesForKeysWithDictionary:modiDic];
NSLog(@"%@%@%@%@",add.country,add.province,add.city,add.district);
KVC處理非對象和自定義對象 (這里就不舉例了!!!)
不是每一個方法都返回對象,但是valueForKey:總是返回一個id對象,如果原本的變量類型是值類型或者結構體,返回值會封裝成NSNumber或者NSValue對象。這兩個類會處理從數字,布爾值到指針和結構體任何類型。然后開以者需要手動轉換成原來的類型。盡管valueForKey:會自動將值類型封裝成對象,但是setValue:forKey:卻不行。你必須手動將值類型轉換成NSNumber或者NSValue類型,才能傳遞過去。
對于自定義對象,KVC也會正確地設值和取值。因為傳遞進去和取出來的都是id類型,所以需要開發者自己擔保類型的正確性,運行時Objective-C在發送消息的會檢查類型,如果錯誤會直接拋出異常。
KVC自帶的運算
①簡單集合運算符
@sum @avg @count @min @max 相信大家都知道這些運算符的意思
②對象運算符 返回值都是NSArray
@distinctUnionOfObjects //獲取去重后的元素
@unionOfObjects//獲取所有的元素
Book *book1 = [[Book alloc]init];
book1.name = @"ios";
book1.price = 12;
Book *book2 = [[Book alloc]init];
book2.name = @"ios2";
book2.price = 15;
Book *book3 = [[Book alloc]init];
book3.name = @"ios3";
book3.price = 111;
Book *book4 = [[Book alloc]init];
book4.name = @"ios1";
book4.price = 111;
NSArray *arrBooks = @[book1,book2,book3,book4];
NSNumber *sum = [arrBooks valueForKeyPath:@"@sum.price"];
NSLog(@"sum = %f",sum.floatValue);
NSNumber *avg = [arrBooks valueForKeyPath:@"@avg.price"];
NSLog(@"avg = %f",avg.floatValue);
NSNumber *count = [arrBooks valueForKeyPath:@"@count"];
NSLog(@"count = %f",count.floatValue);
NSNumber *min = [arrBooks valueForKeyPath:@"@min.price"];
NSLog(@"min = %f",min.floatValue);
NSNumber *max = [arrBooks valueForKeyPath:@"@max.price"];
NSLog(@"max = %f",max.floatValue);
NSLog(@"distinctUnionOfObjects");//獲取去重后的元素
NSArray *arrDistinch = [arrBooks valueForKeyPath:@"@distinctUnionOfObjects.price"];
NSLog(@"arrDis = %@",arrDistinch);
NSLog(@"UnionOfObjects");//獲取所有元素
NSArray *arrUnion = [arrBooks valueForKeyPath:@"@unionOfObjects.price"];
NSLog(@"arrUnion = %@",arrUnion);
總結:KVC常用的兩種用法就 對私有變量訪問和賦值 和 字典轉模型。
對于KVC如果你有好的見解歡迎隨時指教!