1. KVC
- KVC的全稱是
Key-Value Coding
,俗稱“鍵值編碼”,可以通過一個key來訪問某個屬性。 - 常見的API有:
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;//通過keyPath可以設置屬性的屬性
- (void)setValue:(id)value forKey:(NSString *)key;//通過key設置自己的屬性
- (id)valueForKeyPath:(NSString *)keyPath;//通過keyPath訪問屬性的屬性
- (id)valueForKey:(NSString *)key; //通過key訪問自己的屬性
-
kvc設置屬性原理:
kvc設置屬性原理 -
setValue:forKey
的原理詳解:- 先去尋找
setKey:
方法(即對應key的set方法),找到了就去傳遞參數調用方法; - 如果沒找到,再去尋找
_setKey:
的方法,找到可傳值; - 沒找到就去查看
+ (BOOL)accessInstanceVariablesDirectly;
這個方法是不是設置為YES(默認是YES),如果設置的是YES這表示直可以接訪問實例成員變量; - 然后會去查看有沒有
_key
的成員變量、有就設值; - 沒有就去查看有沒有
_isKey
的成員變量、有就設值; - 沒有就去查看有沒有
key
的成員變量、有就設值; - 沒有就去查看有沒有
isKey
的成員變量、有就設值; - 如果還沒找到就會拋異常:
NSUnknownKeyException
- 如果上面
accessInstanceVariablesDirectly
設置為NO,并且setKey:、_setKey:
這兩個set方法沒找到就會拋異常,不會去訪問屬性。
示例1:
- 先去尋找
@interface Person : NSObject{
@public
// int _age;
int _isAge;
int age;
int isAge;
}
/**age屬性*/
//@property(nonatomic,assign) int age;
@end
@implementation Person
//-(void)setAge:(int)age{
// _age = age;
//}
//-(void)_setAge:(int)age{
// _age = age;
//}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person * p = [[Person alloc]init];
[p setValue:@18 forKey:@"age"];
// NSLog(@"%d",p->age);
}
return 0;
}
kvc設置屬性原理
上面代碼和調試結果可以看出:當把兩個set方法和_age
成員變量注銷后會優先訪問_isAge
成員變量,可以通過注銷其他的成員變量一次證明方法的順序,這里不再贅述。
在Person類中重寫+ (BOOL)accessInstanceVariablesDirectly;
方法,并設置返回值為NO
,編譯就會拋異常。
@implementation Person
+ (BOOL)accessInstanceVariablesDirectly{
return NO;
}
@end
拋異常.png
-
kvc取值原理:
kvc取值原理.png - valueForKey:原理詳解:
- 同設置屬性一樣,取值時訪問方法的順序是
getKey
、key
、isKey
、_key
,找到前面的方法就調用給成員變量取值就不會再往下找了。 - 如果上面的方法都沒找到就會去查看accessInstanceVariablesDirectly`這個方法是不是設置為YES,如果設置的是YES這表示直可以接訪問實例成員變量;
- 設置成員變量的順序為:
_key
、_isKey
、key
、iskey
找到前面的成員變量取值就不會再往下找了; - 如果沒有找到上面的成員變量,就會拋異常:
NSUnknownKeyException
- 如果上面
accessInstanceVariablesDirectly
設置為NO,并且上面的方法都沒有找到也會拋異常。
-
注意
:上面的賦值取值方法以及成員變量可以是私有的,依然可以訪問,即KVC是可以訪問對象的私有屬性的。
//.m文件
#import "Person.h"
@interface Person(){
@private
int _age;
int _isAge;
int age;
int isAge;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person * p = [[Person alloc]init];
[p setValue:@18 forKey:@"age"];
NSLog(@"%@",[p valueForKey:@"age"]);
}
return 0;
}
kvc訪問私有屬性.png