前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ios KVO 官方文档学习

ios KVO 官方文档学习

作者头像
onety码生
发布2018-11-21 11:51:53
4360
发布2018-11-21 11:51:53
举报
文章被收录于专栏:码生码生

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

原理说明

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 略作说明

代码语言:javascript
复制
每个对象都有 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 通知
代码语言:javascript
复制
    + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
 
    BOOL automatic = NO;
    if ([theKey isEqualToString:@"balance"]) {
        automatic = NO;
    }
    else {
        automatic = [super automaticallyNotifiesObserversForKey:theKey];
    }
    return automatic;
}
  • 触发 KVO
代码语言:javascript
复制
// 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 方法 发送更改通知
代码语言:javascript
复制
- (void)setBalance:(double)theBalance {
    [self willChangeValueForKey:@"balance"];
    _balance = theBalance;
    [self didChangeValueForKey:@"balance"];
}
代码语言:javascript
复制
- (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"];
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.06.06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 原理说明
    • 关于 KVO 内部实现的原理,官方也就一句话带过
      • 为什么要实现一个中间类呢?
      • 官方文档重点翻译
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档