面試題
1. 通過KVC修改屬性會(huì)觸發(fā)KVO么挺狰?
- 會(huì)觸發(fā)KVO
代碼例子佐證
@interface Person : NSObject
@property (assign, nonatomic) int age;
@end
@interface Observer : NSObject
@end
@implementation Observer
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSLog(@"observeValueForKeyPath - %@", change);
}
@end
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Observer.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Observer *observer = [[Observer alloc] init];
Person *person = [[Person alloc] init];
// 添加KVO監(jiān)聽
[person addObserver:observer forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
// 通過KVC修改age屬性
[person setValue:@10 forKey:@"age"];
// 移除KVO監(jiān)聽
[person removeObserver:observer forKeyPath:@"age"];
}
return 0;
}
運(yùn)行結(jié)果
KVC.png
2. KVC的賦值和取值過程是怎樣的?原理是什么昔案?
- 詳情見下文的valueForKey:的原理圖
序言
KVC的全稱是Key-Value Coding,俗稱“鍵值編碼”,可以通過一個(gè)key來訪問某個(gè)屬性
-
常見的API有
- -(void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- -(void)setValue:(id)value forKey:(NSString *)key;
- -(id)valueForKeyPath:(NSString *)keyPath;
- -(id)valueForKey:(NSString *)key;
setValue:forKey:的原理
image.png
代碼例子佐證
accessInstanceVariablesDirectly返回NO
// 默認(rèn)的返回值就是YES
+ (BOOL)accessInstanceVariablesDirectly {
return NO;
}
image.png
-
accessInstanceVariablesDirectly
返回YES,并且有下劃線成員變量
@interface Person : NSObject {
@public
int age;
int isAge;
int _isAge;
int _age;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Person *person = [[Person alloc] init];
// 通過KVC修改age屬性
[person setValue:@10 forKey:@"age"];
NSLog(@"%@", [person valueForKey:@"age"]);
}
return 0;
}
運(yùn)行結(jié)果
image.png
可以將變量依次注釋,看看打印結(jié)果
age
,isAge
砾嫉,_isAge
,_age
@public
int age;
int isAge;
// int _isAge;
// int _age;
}
運(yùn)行結(jié)果
image.png
valueForKey:的原理
valueForKey.png
- 代碼例子佐證 - 先找方法
@implementation Person
// 第一順序調(diào)用
- (int)getAge {
return 11;
}
// 第二順序調(diào)用
- (int)age {
return 12;
}
// 第三順序調(diào)用
- (int)isAge {
return 13;
}
// 第四順序調(diào)用
- (int)_age {
return 14;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Person *person = [[Person alloc] init];
NSLog(@"%@", [person valueForKey:@"age"]);
}
return 0;
}
- 依次注釋掉方法
getAge
窒篱,age
焕刮,isAge
舶沿,_age
,然后打印結(jié)果如下
getAge.png
age.png
isAge.png
_age.png
- 代碼例子佐證 - 再找成員變量
@interface Person : NSObject {
@public
int age;
int isAge;
int _isAge;
int _age;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Person *person = [[Person alloc] init];
// 通過KVC修改age屬性
person->_age = 100;
person->_isAge = 110;
person->age = 120;
person->isAge = 130;
NSLog(@"%@", [person valueForKey:@"age"]);
}
return 0;
}
- 依次在Person.h文件中注釋成員變量
_age
配并,_isAge
括荡,age
,isAge
荐绝,然后查看打印結(jié)果
_age.png
_isAge.png
age.png
isAge.png
如果將方法和成員變量全部去掉一汽,打印結(jié)果如下
image.png
由打印結(jié)果可知,如果方法和成員變量都找不到低滩,則最終方法找不到的錯(cuò)誤召夹。
本文參考借鑒MJ的教程視頻,非常感謝.