🌰 :動畫
首先建立一個YJCPerson類,該類有三個屬性,分別是name,age和一個YJCDog,YJCDog有一個dogName屬性atom
@interface YJCPerson : NSObject + (instancetype)personWithName:(NSString *)name age:(NSInteger)age dogName:(NSString *)dogName; - (instancetype)initWithName:(NSString *)name age:(NSInteger)age dogName:(NSString *)dogName; @end #import "YJCPerson.h" #import "YJCDog.h" @interface YJCPerson () @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) NSInteger age; @property (nonatomic, strong) YJCDog *dog; @end @implementation YJCPerson + (instancetype)personWithName:(NSString *)name age:(NSInteger)age dogName:(NSString *)dogName{ YJCPerson *person = [[self alloc]initWithName:name age:age dogName:dogName];return person; } - (instancetype)initWithName:(NSString *)name age:(NSInteger)age dogName:(NSString *)dogName{ if (self = [self init]) { self.name = name; self.age = age; self.dog.dogName = dogName; } return self; } - (instancetype)init{ if (self = [super init]) { self.dog = [YJCDog new]; } return self; } @end
對於一個類,最好有便利構造方式spa
在VC中對該類添加監看指針
#import "ViewController.h" #import "YJCPerson.h" @interface ViewController () @property (nonatomic, strong) YJCPerson *person; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil]; [self.person addObserver:self forKeyPath:@"dog.dogName" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil]; [self.person setValue:@"YJC" forKey:@"name"];//KVC的setValue:forKey: [self.person setValue:@"大黃" forKeyPath:@"dog.dogName"];//KVC的setValue:forKeyPath:
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:@"name"])
{
NSLog(@"YJCPerson 更名了,%@-->%@",[change valueForKey:@"old"],[change valueForKey:@"new"]);
}
else if ([keyPath isEqualToString:@"dog.dogName"])
{
NSLog(@"YJCPerson.dog 更名了,%@-->%@",[change valueForKey:@"old"],[change valueForKey:@"new"]);
}
}
- (YJCPerson *)person
{
return _person?:({
_person = [[YJCPerson alloc]init];
[_person setValue:@"name" forKey:@"name"];
[_person setValue:@"dog" forKeyPath:@"dog.dogName"];
_person;
});
}
//若是添加了KVO,必定要記得釋放
- (void)dealloc
{
[self removeObserver:self.person forKeyPath:@"name"];
[self removeObserver:self.person forKeyPath:@"dog.dogName"];
}
@end
KVC主要是經過鍵值路徑得到相應的屬性,而且能夠得到私有屬性code
那麼它獲取路徑的順序是什麼呢server
- (NSString *)getName;對象
- (NSString *)name;blog
- (NSString *)isName;rem
首先會依次查找這三個方法,固然既然聲明的是屬性,那麼系統就默認實現了getter方法,因此會在第一步就找到.get
那麼若是這三個方法都沒有找到呢
由於name是string類型的,不不太明顯.若是是array類型的話,系統會繼續找響應的方法
例如-(id)objectInNameAtIndex:(NSUInteger)index;
若是依然沒有找到,那麼系統就會找- (id)valueForUndefineKey:(NSString *)key;若是該方法內依然沒有找到相關key,則會crash,因此咱們能夠經過從新該方法來防止程序crash
現實中KVC主要作的工做是對一些系統類的私有屬性的賦值,像設置佔位字符顏色啦,動畫的一些屬性啦什麼的
KVO
KVO呢用法就是經過對某一實例的相關屬性添加監看,系統會執行回調,切記添加了KVO必定要記得釋放,寫法呢大概就這個樣子,示例而已
KVO的實現呢主要是該機制爲被監控對象建立了一個分類NSKVONotifying_Class Class就是被監看的實例所屬類.而後該機制會重寫該屬性的setter方法,setter在調用原setter方法以前和以後,經過KVO機制通知全部監看對象
固然這些行爲是隱藏的,系統會經過runtime建立該分類,並把被監看對象的isa指針指向該分類,既然isa指針指向了該分類,那麼setter方法天然就是調用該分類裏已經重寫過的setter方法咯,重寫的時候添加了willChange和didChange兩個方法用來通知監看對象
還有一點:遵循KVO賦值的方式纔會觸發KVO,直接對實例變量賦值是不會觸發KVO機制的
切記,添加了監看必定要移除監看