美文网首页
ios KVO 官方文档学习

ios KVO 官方文档学习

作者: wangtieshan | 来源:发表于2018-06-06 15:19 被阅读0次

    从官方文档来武装一下自己(游击队->正规军)

    原理说明

    When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance.

    • 当对一个类添加观察后,这个类的 isa 指针被指向了一个中间类,而非真实的了类

    关于 KVO 内部实现的原理,官方也就一句话带过

    而这个中间类和 isa 就是 KVO 的核心了

    为什么要实现一个中间类呢?

    KVO的核心在于,属性的改变的时候,可以兼容的到

    我们一般在更改属性值的时候一般都是

    1. 点方法 -> setter 方法
    2. setValueForKey
    3. 直接赋值

    对于直接赋值,这个属于直接修改了指针的指向,这个就很难抓到了

    所以重点看 setter 方法 和 setValueForKey 这两个方法

    于是 KVO 就要在运行的时候动态的兼容我们的 setter 方法

    那么苹果的实现方法就是,运行时新建了一个被观察的对象的子类

    将被观察对象的 isa 指针指向子类

    isa 略作说明

    
    每个对象都有 isa 指针,isa 指针存储了一个类所有的信息。
    
    例如:所有的方法、所有的属性
    
    换句话来说,我们对 OC 类的操作,底层都是对 isa 指针的操作
    
    例如: isKindOf 方法
    
    其源码可以看出
    
    对象 -> isa -> isa_class -> isa_super_class 直到找到 isa 类型相等
    
    没有找到则 return false,找到则 return true
    
    

    子类重写了 setter 方法,然后就可以抓到属性的改变了

    至于怎么通知给观察者改变的,看下面的 官方文档重点翻译

    官方文档重点翻译

    • OS X 中,model and controller layers 很大程度省依赖 KVO

    if your objects inherit from NSObject and you create properties in the usual way, your objects and their properties will automatically be KVO Compliant. It is also possible to implement compliance manually

    • 继承自 NSObject 的类,常规的方式创建的属性,都自动的可以使用 KVO

    Not all classes are KVO-compliant for all properties

    • 并不是所有的属性都兼容 KVO

    Manual change notification provides additional control over when notifications are emitted, and requires additional coding. You can control automatic notifications for properties of your subclass by implementing the class method [automaticallyNotifiesObserversForKey:](https://developer.apple.com/documentation/objectivec/nsobject/1409370-automaticallynotifiesobservers).

    • 重写子类的 automaticallyNotifiesObserversForKey: 可以来控制属性的改变是否发送 KVO 通知
        + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
     
        BOOL automatic = NO;
        if ([theKey isEqualToString:@"balance"]) {
            automatic = NO;
        }
        else {
            automatic = [super automaticallyNotifiesObserversForKey:theKey];
        }
        return automatic;
    }
    
    • 触发 KVO
    // Call the accessor method.
    [account setName:@"Savings"];
     
    // Use setValue:forKey:.
    [account setValue:@"Savings" forKey:@"name"];
     
    // Use a key path, where 'account' is a kvc-compliant property of 'document'.
    [document setValue:@"Savings" forKeyPath:@"account.name"];
     
    // Use mutableArrayValueForKey: to retrieve a relationship proxy object.
    Transaction *newTransaction = <#Create a new transaction for the account#>;
    NSMutableArray *transactions = [account mutableArrayValueForKey:@"transactions"];
    [transactions addObject:newTransaction];
    
    • 重写 setter 方法 发送更改通知
    - (void)setBalance:(double)theBalance {
        [self willChangeValueForKey:@"balance"];
        _balance = theBalance;
        [self didChangeValueForKey:@"balance"];
    }
    
    - (void)removeTransactionsAtIndexes:(NSIndexSet *)indexes {
        [self willChange:NSKeyValueChangeRemoval
            valuesAtIndexes:indexes forKey:@"transactions"];
     
        // Remove the transaction objects at the specified indexes.
     
        [self didChange:NSKeyValueChangeRemoval
            valuesAtIndexes:indexes forKey:@"transactions"];
    }
    

    相关文章

      网友评论

          本文标题:ios KVO 官方文档学习

          本文链接:https://www.haomeiwen.com/subject/xrvbsftx.html