如果要更改對象屬性可以通過什么方法達到呢?
(1)通過setter和getter方法。
(2)屬性。
(3)直接設置實例變量。
今天學習新的一種方法:鍵值編碼-kvc。通過指定要訪問的屬性名字的字符串標識符,可以進行類的屬性的讀取和設置。
鍵值編碼基本調用包括:setValue:forKey:和valueForKey。
栗子:
新建Student類,屬性及成員變量:
@interface Student : NSObject{ @public NSString * name; @PRivate NSString * hobby;}@property(strong,nonatomic) NSString * address;@property(nonatomic) int age;@end
通過setter和getter方法、屬性可以設置屬性:
Student * stu1 = [Student new]; stu1->name = @"haha"; NSLog(@"%@",stu1->name); stu1.address = @"street"; //屬性可通過點語法設置 stu1.age = 100; NSLog(@"address:%@,age:%d",stu1.address,stu1.age);
***下邊通過鍵值編碼kvc設置***
Student * stu1 = [Student new]; [stu1 setValue:@"kvcName" forKey:@"name"]; NSLog(@"kvc設置name:%@",[stu1 valueForKey:@"name"]); [stu1 setValue:@18 forKey:@"age"]; //int基本型的需要包裝成oc對象型的 NSLog(@"kvc設置age:%@",[stu1 valueForKey:@"age"]);
通過kvc也可以設置屬性,甚至于private的成員變量也可以設置,Student類中有一個private的成員變量:hobby
//private的屬性仍然能夠通過kvc設置,所以kvc破壞了面向對象的封裝思想 [stu1 setValue:@"read" forKey:@"hobby"]; NSLog(@"%@",[stu1 valueForKey:@"hobby"]);
既然都可以設置屬性,那么kvc和其他的有什么區別呢?它的使用場景是什么呢?
1:
key返回NSString類型的字符串??梢詥为毺岢鰜恚?/p>
Student * stu1 = [Student new]; NSString * key = @"name"; //變量 靈活 //[stu1 setValue:@"kvcName" forKey:@"name"]; [stu1 setValue:@"kvcName" forKey:key]; NSLog(@"kvc設置name:%@",[stu1 valueForKey:@"name"]);
這樣key相當于是一個中間變量,無疑大大增強了靈活性。
2:類似id型對象不能點語法的,那么可以通過kvc設置。如:
id obj = stu1; //id 不能通過點語法設置屬性 obj.name = @"hehe"; //報錯 [obj setValue:@"idName" forKey:@"name"]; NSLog(@"id設置的name:%@",[obj valueForKey:@"name"]);
kvc首先查找的是setter命名的屬性,為證實,重寫setter,如果setter被調用則可以證實。
以Student的name成員變量為例,寫setter方法:
- (void)setName:(NSString *)newName{ NSLog(@"kvc......"); self->name = newName;}
如果被調用則會打印kvc......,
main函數中:
Student * stu1 = [Student new]; NSString * key = @"name"; [stu1 setValue:@"kvcName" forKey:key]; NSLog(@"kvc設置name:%@",[stu1 valueForKey:@"name"]);
打印結果:
驗證了。。。。。。如果不存在getter呢?也就是說不能用屬性(屬性會自動生成setter和getter方法),那么則會在對象內部查找_key或key的實例變量。
以Student的hobby為例,它不是屬性,用沒有寫setter方法,現在聲明hobby和_hobby,為了驗證寫了一個test方法:
@interface Student : NSObject{ @public NSString * name; @private NSString * hobby; NSString * _hobby;}@property(strong,nonatomic) NSString * address;@property(nonatomic) int age;- (void)test;
test方法:
- (void)test{ NSLog(@"_hobby = %@",self->_hobby); NSLog(@"hobby = %@",self->hobby);}
那么當main中hobby通過kvc設置的時候,會發生什么?
Student * stu1 = [Student new]; [stu1 setValue:@"read" forKey:@"hobby"]; [stu1 test];
按說這是給hobby設置值,打印結果:
結果_hobby上有值,這就證實kvc先查找_key。
注意:使用@property+@synthesize可以自動生成getter和setter,但是如果為其指定非標準的getter和setter,key的搜索則會出現問題。
設想以下情況:添加一個Brother類,Student有一個屬性是Brother對象。
@interface Student : NSObject{ @public NSString * name; @private NSString * hobby; NSString * _hobby;}@property(strong,nonatomic) NSString * address;@property(nonatomic) int age;//添加brother屬性@property(strong,nonatomic)Brother * brother;- (void)setName:(NSString *)newName;- (void)test;@end
而Brother類下有一個屬性broName?,F在有這么一個需求:我需要通過Student給brother下的broName賦值。(不是通過brother)
那么代碼似乎應該這么寫:
Student * stu1 = [Student new]; Brother * bro1 = [Brother new]; stu1.brother = bro1; [stu1 setValue:@"兄弟" forKey:@"bro1.broName"]; NSLog(@"%@",[bro1 valueForKey:@"broName"]); //崩潰
這么寫代碼崩潰,那該怎么寫呢?使用鍵路徑:setValue:forKeyPath:
假設a對象下有一個名為b的屬性,而b中包含了名稱為c的屬性,如果想要從a獲?。ɑ蛟O置)c屬性的內容需要使用如下路徑來描述: b.c (遇到點會解析成路徑)
Student * stu1 = [Student new]; Brother * bro1 = [Brother new]; stu1.brother = bro1; [stu1 setValue:@"兄弟" forKeyPath:@"brother.broName"]; NSLog(@"%@",[stu1 valueForKeyPath:@"brother.broName"]);
這樣就可以了,上面的代碼稍作修改:現在brother下有一個brother對象brotherOld屬性,該怎么賦值呢?
@interface Brother : NSObject@property(strong,nonatomic) NSString * broName;@property(strong,nonatomic) Brother * brotherOld;@end
這樣相當于通過兩層去設置值。
Student * stu1 = [Student new]; Brother * bro1 = [Brother new]; stu1.brother = bro1; Brother * bigBrother = [Brother new]; bro1.brotherOld = bigBrother; [stu1 setValue:@"大兄弟" forKeyPath:@"brother.brotherOld.broName"]; NSLog(@"%@",[stu1 valueForKeyPath:@"brother.brotherOld.broName"]);
為一個不存在的鍵setValue forKey的話,會報錯,比如:
[stu1 setValue:@"mei you zhe ge jian" forKey:@"notExist"]; //崩潰
可以實現setValue:forUndefinedKey:
Student下聲明一個字典:NSMutableDictionary * undefinedKeysAndValues可以存到這個字典中(相當于臨時容器)
Student.m文件
//以下兩個方法一般不重寫-(void)setValue:(id)value forUndefinedKey:(NSString *)key{ NSLog(@"呵呵,你所訪問的鍵:%@不存在,你就別想把值:%@放到這個鍵上了,說的就跟你有這個鍵似的!",key,value); //[self->undefinedKeysAndValues setObject:value forKey:key];}-(id)valueForUndefinedKey:(NSString *)key{ NSLog(@"對不起,沒有這樣的鍵!"); return nil; //return [self->undefinedKeysAndValues objectForKey:key];}@end
NSDictionary * dict = @{@"aaa":@"11111111",@"bbb":@"22222222222"}; //NSLog(@"%@",[dict objectForKey:@"aaa"]); NSLog(@"%@",[dict valueForKey:@"aaa"]);
打印結果:
2015-11-06 19:40:30.445 oc-kvc-001[846:61032] 11111111
Program ended with exit code: 0
本來字典的取值是通過objectForKey,現在也能通過valueForKey取值,說明valueForKey是NSobject的方法,字典繼承自NSobject
如果對象的某個實例變量為NSArray,而其中存放的又是對象。
Team.h文件:
@interface Team : NSObject@property(strong,nonatomic) NSArray * members;@end
Student.h文件:
@interface Student : NSObject@property(copy,nonatomic) NSString * name;@property(nonatomic) int age;@end
Team下有一個屬性為members的數組,members數組中存放的是Student對象。
Student * s1 = [Student new]; s1.name = @"學生甲"; s1.age = 1000; Student * s2 = [Student new]; s2.name = @"學生乙"; s2.age = 28; Student * s3 = [Student new]; s3.name = @"學生丙"; s3.age = 1100; Student * s4 = [Student new]; s4.name = @"學生丁"; s4.age = 1400; NSArray * arr = @[s1,s2,s3,s4]; //對NSArray請求一個鍵值,則會查詢數組中的每一個對象來查找這個鍵,然后將這些結果重新打包為一個NSArray id ages = [arr valueForKey:@"age"]; NSLog(@"%@",ages);
//可以取最大值、最小值、求和、平均值、個數。 id maxAge = [arr valueForKeyPath:@"@max.age"]; id minAge = [arr valueForKeyPath:@"@min.age"]; id sumAge = [arr valueForKeyPath:@"@sum.age"]; id avgAge = [arr valueForKeyPath:@"@avg.age"]; id count = [arr valueForKeyPath:@"@count"]; NSLog(@"%@,%@,%@,%@,%@",maxAge,minAge,sumAge,avgAge,count); Team * team = [Team new]; team.members = arr; maxAge = [team valueForKeyPath:@"members.@max.age"]; minAge = [team valueForKeyPath:@"members.@min.age"]; sumAge = [team valueForKeyPath:@"members.@sum.age"]; avgAge = [team valueForKeyPath:@"members.@avg.age"]; count = [team valueForKeyPath:@"members.@count"]; NSLog(@"%@,%@,%@,%@,%@",maxAge,minAge,sumAge,avgAge,count);
啊╮(╯▽╰)╭,結束。。。。。。。。
新聞熱點
疑難解答