OC--KVO

高质量博客
sunnyxx:《objc kvo简单探索》
南峰子的技术博客:NSKeyValueObserving(KVO)
Facebook开源的KVOController
Facebook开源的KVOController源码解读
青少年一定要读的KVO指南

KVO的原理

简而言之就是:
1、当对象有观察者时,系统runtime动态创建对象的子类、重写class方法返回父类(隐藏自己),对象的isa指向这个新类;
2、对象被观察的属性,新类重写setter方法,执行setter前后通知属性的所有观察者;
3、当一个属性没有观察者时候,删除重写的setter方法;
4、当对象没有观察者时候(移除监听),删除动态创建的子类;

OC--KVO_第1张图片
1727535-a493b5a7178036ea.jpg
记录一下不常用的用法
NSKeyValueObservingOptions
typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {
    // 提供属性的新值
    NSKeyValueObservingOptionNew = 0x01,
    // 提供属性的旧值
    NSKeyValueObservingOptionOld = 0x02,
    
    // 如果指定,则在添加观察者的时候立即发送一个通知给观察者
    NSKeyValueObservingOptionInitial NS_ENUM_AVAILABLE(10_5, 2_0) = 0x04,
    
    // 如果指定,则在每次修改属性时,会在修改通知被发送之前预先发送一条通知给观察者
    // 这与-willChangeValueForKey:被触发的时间是相对应的
    NSKeyValueObservingOptionPrior NS_ENUM_AVAILABLE(10_5, 2_0) = 0x08
};

NSKeyValueObservingOptionInitial

    self.name = @"1";
    NSLog(@"监听前");
    [self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionInitial |NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
    NSLog(@"监听后,修改前");
    self.name = @"2";
    NSLog(@"修改后");
    
    /* NSLog
    监听前
    keyPath=name change={
        kind = 1;
        new = 1;
    }
    监听后,修改前
    keyPath=name change={
        kind = 1;
        new = 2;
        old = 1;
    }
    修改后
     */

NSKeyValueObservingOptionPrior

    self.name = @"1";
    
    NSLog(@"监听前");
    [self addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionPrior |NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
    NSLog(@"监听后,修改前");
    self.name = @"2";
    NSLog(@"修改后");

    /* NSLog
    监听前
    监听后,修改前
    keyPath=name change={
        kind = 1;
        notificationIsPrior = 1;
        old = 1;
    }
    keyPath=name change={
        kind = 1;
        new = 2;
        old = 1;
    }
    修改后
     */

依赖设置

@interface ViewController ()
@property (nonatomic, strong) NSString *fullName;
@property (nonatomic, strong) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;
@end

@implementation ViewController

// fullName依赖firstName和lastName
- (NSString *)fullName {
    
    return [NSString stringWithFormat:@"%@ %@",_firstName,_lastName];
}

+ (NSSet *)keyPathsForValuesAffectingFullName {
    
    return [NSSet setWithObjects:@"firstName", @"lastName", nil];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    [self addObserver:self forKeyPath:@"fullName" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
    self.firstName = @"lao";
    self.lastName = @"wang";

    /*NSLog
     keyPath=fullName change={
     kind = 1;
     new = "lao (null)";
     old = "(null) (null)";
     }
     keyPath=fullName change={
     kind = 1;
     new = "lao wang";
     old = "lao (null)";
     }
     */

}

集合属性 如:NSMutableArray、NSMutableSet、NSMutableOrderedSet

    [self addObserver:self forKeyPath:@"nameArr" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:NULL];
    
    self.nameArr = [[NSMutableArray alloc] init]; // 触发KVO
    
    [self.nameArr addObject:@"1"];              // 这么操作不触发KVO
    
    NSMutableArray *arr = [self mutableArrayValueForKey:@"nameArr"];
    // 使用mutableArrayValueForKey获得集合,操纵addObject
    // 下面都触发KVO
    [arr addObject:@"2"];
    [arr replaceObjectAtIndex:0 withObject:@"3"];
    [arr removeAllObjects];

你可能感兴趣的:(OC--KVO)