_person = [[Person alloc] init];
/**
* 添加觀察者
*
* @param observer 觀察者
* @param keyPath 被觀察的屬性名稱
* @param options 觀察屬性的新值、舊值等的一些配置(枚舉值,能夠根據須要設置,例如這裏可使用兩項)
* @param context 上下文,能夠爲nil。
*/
[_person addObserver:self
forKeyPath:@"age"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
/**
* KVO 回調方法
*
* @param keyPath 被修改的屬性
* @param object 被修改的屬性所屬對象
* @param change 屬性改變狀況(新舊值)
* @param context context 傳過來的值
*/
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSString *,id> *)change
context:(void *)context
{
NSLog(@"%@ 對象的%@屬性改變了:%@",object,keyPath,change);
}
/**
* 移除觀察者
*/
- (void)dealloc
{
[self.person removeObserver:self forKeyPath:@"age"];
}
複製代碼
[scrollview addObserver:self
forKeyPath:@「contentOffset
options:NSKeyValueObservingOptionNew
context:nil];
複製代碼
【註冊】1.// 註冊觀察者,實施監聽;
[self.person addObserver:self
forKeyPath:@"age"
options:NSKeyValueObservingOptionNew
context:nil];
【觀察】2.// 觀察方法,回調方法,在這裏處理屬性發生的變化;
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSString *,id> *)change
context:(void *)context
【移除】3.// 移除觀察者;
[self removeObserver:self forKeyPath:@「age"];
複製代碼
KVC 缺點數組
NSArray *a = @[@4, @84, @2];
NSLog(@"max = %@", [a valueForKeyPath:@"@max.self"]);
複製代碼
NSArray *a = @[transaction1, transaction2, transaction3];
NSLog(@"max = %@", [a valueForKeyPath:@"@max.amount"]);
複製代碼
@interface Teacher : NSObject
{
@private int _age;// 私有變量,通常外部不能改變,經過kvc能夠改變,前提你知道這個私有變量的名字;
}
@property (nonatomic, strong, readonly) NSString *name;// 只讀變量,一個外部不能直接賦值,經過kvc能夠改變
@property (nonatomic, assign, getter = isMale) BOOL male;
- (void)log;
@end
複製代碼
Teacher *teacher = [Teacher new];
[teacher log];
// 設置 readonly value
[teacher setValue:@"Jack" forKey:@"name"];
// teacher.name = @"Jack";
// 設置 private value
[teacher setValue:@24 forKey:@"age"];
// teacher.age = 24;
[teacher setValue:@1 forKey:@"male"];
[teacher log];
// 獲取 readonly value
NSLog(@"name: %@", [teacher valueForKey:@"_name"]);
// 獲取 private value
NSLog(@"age: %d", [[teacher valueForKey:@"_age"] intValue]);
NSLog(@"male: %d", [[teacher valueForKey:@"isMale"] boolValue]);
複製代碼
[_textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
[_textField setValue:[UIFont systemFontOfSize:14] forKeyPath:@「_placeholderLabel.font"];
複製代碼
[_pageControl setValue:[UIImage imageNamed:@"selected"] forKeyPath:@"_currentPageImage"];
[_pageControl setValue:[UIImage imageNamed:@"unselected"] forKeyPath:@"_pageImage"];
複製代碼
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
複製代碼
key 和keypath的區別?markdown
key只能接受當前類所具備的屬性,無論是本身的,仍是從父類繼承過來的,如view.setValue(CGRectZero(),key: "frame");函數
keypath: 除了能接受當前類的屬性,還能接受當前類屬性的屬性,便可以接受關係鏈,如view.setValue(5,keypath: "layer.cornerRadius」)編碼
舉個例子說明問題1:atom
例子:好比person有個屬性是address,address有個屬性是town,如今咱們如何經過person訪問town屬性?spa
答:若是經過key來訪問指針
id address = [person valueForKey:@"address"];
id town = [address valueForKey:@"town」];
// 若是經過keypath來訪問
id town = [person valueForKeyPath:@"address.town"];
複製代碼
// value 的值爲OC對象,若是是基本數據類型要包裝成NSNumber
- (void)setValue:(id)value forKey:(NSString *)key;
// keyPath 鍵路徑,類型爲xx.xx
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
// 它的默認實現是拋出異常,能夠重寫這個函數作錯誤處理。
- (void)setValue:(id)value forUndefinedKey:(NSString *)key;
複製代碼
- (id)valueForKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
// 若是Key不存在,且沒有KVC沒法搜索到任何和Key有關的字段或者屬性,則會調用這個方法,默認是拋出異常
- (id)valueForUndefinedKey:(NSString *)key;
複製代碼
// 容許直接訪問實例變量,默認返回YES。若是某個類重寫了這個方法,且返回NO,則KVC不能夠訪問該類。
+ (BOOL)accessInstanceVariablesDirectly;
// 這是集合操做的API,裏面還有一系列這樣的API,若是屬性是一個NSMutableArray,那麼能夠用這個方法來返回
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
// 若是你在setValue方法時面給Value傳nil,則會調用這個方法
- (void)setNilValueForKey:(NSString *)key;
// 輸入一組key,返回該組key對應的Value,再轉成字典返回,用於將Model轉到字典。
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
// KVC 提供屬性值確認的API,它能夠用來檢查set的值是否正確、爲不正確的值作一個替換值或者拒絕設置新值並返回錯誤緣由。
- (BOOL)validateValue:(id)ioValue forKey:(NSString *)inKey error:(NSError)outError;
複製代碼