iOS KVO

KVO主要的幾個方法

  • 添加觀察者
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
複製代碼
  • 移除觀察者
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
複製代碼
  • 觀察回調
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;
複製代碼

參數說明: observer:觀察者,通常傳selfkeyPath:路徑,傳入觀察對象的屬性變量,(成員變量不會生效,由於成員變量沒有setter方法)。 options:枚舉,一共有4個值,最經常使用的爲NSKeyValueObservingOptionNewbash

NSKeyValueObservingOptionNew       新值
    NSKeyValueObservingOptionOld       舊值
    NSKeyValueObservingOptionInitial   觀察最初的值(在註冊觀察服務時會調用一次觸發方法)
    NSKeyValueObservingOptionPrior     分別在值修改先後觸發方法(即一次修改有兩次觸發)
複製代碼

context:打上標籤,在觀察回調中可用於區分,防止繼承。object也能夠達到相似的功能,但object須要遍歷不少東西,context性能更好。不想用的話就傳入NULLobject:被觀察的對象。打印出來是<Person: 0x600001815710>change:發生改變的內容。性能

####KVO的基本用法 1.建立一個類,命名Person,分別添加成員變量與屬性變量。ui

@interface Person : NSObject{
    NSString *nickName;
}
@property(strong,nonatomic)NSString * name;
@property(assign,nonatomic)int age;
@property(strong,nonatomic)NSMutableArray * cars;
@end
複製代碼

2.在控制器中,建立Person對象,給對象添加觀察者。atom

@property(strong,nonatomic)Person *  p;

self.p = [[Person alloc]init];
[self.p addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew) context:NULL];
[self.p addObserver:self forKeyPath:@"age" options:(NSKeyValueObservingOptionNew) context:NULL];
複製代碼

3.添加觀察回調spa

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"改變的內容===%@", change);
    NSLog(@"觀察的對象===%@", object);
}
複製代碼

4.移除觀察者(必須),不移除有可能會致使崩潰。3d

-(void)dealloc{
    [self.p removeObserver:self forKeyPath:@"name"];
}
複製代碼

5.觸發監聽(舉例)code

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    self.p.name = @"尤先森";
    self.p.age ++;
    [[self.p mutableArrayValueForKey:@"cars"] addObject:@"阿斯頓馬丁"];
}
複製代碼

一些騷操做

  • 自動觀察 觀察對象設置自動觀察(與其說是自動,不如說是能夠加限制) 下面這個方法只有key等於name的時候,纔會觸發觀察回調。
+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
    if ([key isEqualToString:@"name"]) {
        return YES;
    }
    return NO;
}
複製代碼
  • 手動觀察 當被上面的方法限制了的話,能夠經過手動觀察讓他恢復觀察
-(void)setAge:(int)age{
    [self willChangeValueForKey:@"age"];
    _age = age;
    [self didChangeValueForKey:@"age"];
}
複製代碼
  • 聯動觀察 當咱們須要觀察一個對象受有多個因素影響時,可進行聯動操做。
// 1.新建3個屬性
@property(assign,nonatomic)double done; //已完成

@property(assign,nonatomic)double total; //總量

@property(strong,nonatomic)NSString *downloadProgress; //下載進度

// 2.關聯屬性
+(NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
    if ([key isEqualToString:@"downloadProgress"]) {
        NSArray *array = @[@"done",@"total"];
        keyPaths = [keyPaths setByAddingObjectsFromArray:array];
    }
    return keyPaths;
}

// 3.添加監聽
[self.p  addObserver:self forKeyPath:@"downloadProgress" options:(NSKeyValueObservingOptionNew) context:NULL];

// 4.觸發
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{    
    self.p.done +=10;
}

//downloadProgress懶加載
-(NSString *)downloadProgress{
    if (self.done == 0) {
        _done = 10;
    }
    if (self.total == 0) {
        _total = 100;
    }
    return [NSString stringWithFormat:@"%f",1.0f*self.done/self.total];
}

複製代碼
  • 對集合類型(NSMutableArray,NSMutableSet)進行操做。
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //按照通常套路將不會回調
    [self.p.cars addObject:@"蘭博基尼"];
    //KVO 中 ,對集合類型(Array,set)操做。
    //取值和賦值過程 跟通常狀況不同,須要經過KVC 的方式。
    [[self.p mutableArrayValueForKey:@"cars"] addObject:@"蘭博基尼"];
}
複製代碼

擴展

因爲KVO並無開源,爲了瞭解KVO內部的實現原理,嘗試 探索KVO底層原理orm

相關文章
相關標籤/搜索