KVO 的本質?

  1. iOS 用什么方式實現對一個對象的 KVO ? (KVO 的本質是什么?)
  • 首先利用 Runtime API 動態(tài)創(chuàng)建一個中間類(NSKVONotifying_ + 類名), 并讓實例對象的 isa 指針指向這個中間類, 當修改實例對象的屬性時, 會調用 Foundation 的 _NSSetxxxValueAndNotify 函數, 該函數內部主要是做 willChangeValueForKey, super 的 setter, didChangeValueForKey, 然后會觸發(fā) Observer 監(jiān)聽方法
  1. 如何手動觸發(fā) KVO?
  • 實例對象先調用 willChangeValueForKey, 然后再調用 didChangeValueForKey
  1. KVO 是否可以添加成員變量的觀察?
  • 可以的, 為成員變量添加 KVO 是可以的但是必須用 KVC 方式賦值

具體觀察代碼, 重點observeValueForKeyPath:

#import "ViewController.h"
#import "Person.h"
#import <objc/runtime.h>

/**
 * 1. iOS 用什么方式實現對一個對象的 KVO ? (KVO 的本質是什么?)
 * 首先利用 Runtime API 動態(tài)創(chuàng)建一個中間類(NSKVONotifying_ + 類名), 并讓實例對象的 isa 指針指向這個中間類, 當修改實例對象的屬性時, 會調用 Foundation 的 _NSSetxxxValueAndNotify 函數, 該函數內部主要是做 willChangeValueForKey, super 的 setter, didChangeValueForKey, 然后會觸發(fā) Observer 監(jiān)聽方法
 * 2. 如何手動觸發(fā) KVO?
 * 實例對象先調用 willChangeValueForKey, 然后再調用 didChangeValueForKey
 */

@interface ViewController ()

@property (nonatomic, strong) Person *person1;
@property (nonatomic, strong) Person *person2;
@end

@implementation ViewController


- (void)dealloc {
    [self.person1 removeObserver:self forKeyPath:@"age"];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.person1 = Person.new;
    self.person1.age = 10;
    self.person2 = Person.new;
    self.person2.age = 20;
    
    // 添加監(jiān)聽
    [self.person1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}


- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    self.person1.age = arc4random() % 100 + 1;
    self.person2.age = arc4random() % 100 + 1;
}

// 當監(jiān)聽對象的屬性值改變時, 就會調用
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    /**
     * 打印 person1 的類對象
     * (lldb) p self.person1.isa
     * (Class) $2 = NSKVONotifying_Person
     * Fix-it applied, fixed expression was:
     * self.person1->isa
     *
     * 打印 person2 的類對象
     * (lldb) p self.person2.isa
     * (Class) $3 = Person
     * Fix-it applied, fixed expression was:
     * self.person2->isa
     *
     * 打印所有方法, 可以 llbd 也可以自己實現一個 _printMethodNamesOfClass
     * (lldb) po [$2 _shortMethodDescription]
     * <NSKVONotifying_Person: 0x600000d40870>:
     * in NSKVONotifying_Person:
     *   Instance Methods:
     *      - (void) setAge:(long)arg1; (0x7fff258e518d)        //  ----- 實際會先調用 _NSSetIntValueAndNotify
     *      - (Class) class; (0x7fff258e2fd5)           //  ----- 重寫 class 實現, class 方法 底層可能就是 object_getClass, 重寫后讓讀者認為還是 Person 類
     *      - (void) dealloc; (0x7fff258e2d3a)      // ---- 收尾工作
     *      - (BOOL) _isKVOA; (0x7fff258e2d32)
     *   in Person:
     *      Properties:
     *          @property (nonatomic) long age;  (@synthesize age = _age;)
     *      Instance Methods:
     *          - (long) age; (0x10e795f90)
     *          - (void) setAge:(long)arg1; (0x10e795fb0)
     *   (NSObject ...)
     */

    [self _printMethodNamesOfClass:object_getClass(object)];
    NSLog(@"%@", change);
}

// 打印所有方法
- (void)_printMethodNamesOfClass:(Class)cls {
    // 定義
    unsigned int outCount = 0;
    Method *methodList = NULL;
    Method tempMethod = NULL;
    NSMutableString *strResult = [NSMutableString string];
    NSString *strTemp = [NSString string];
    
    // copy 出方法列表
    methodList = class_copyMethodList(cls, &outCount);
    
    // 遍歷
    for (int i = 0; i < outCount; ++i) {
        tempMethod = methodList[i];
        strTemp = NSStringFromSelector(method_getName(tempMethod));
        [strResult appendFormat:@"\n%@", strTemp];
    }
    
    NSLog(@"%@", strResult);
}


@end

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 面試問題: iOS用什么方式實現對一個對象的KVO? 如何手動觸發(fā)KVO? KVO簡介 KVO就是鍵值觀測。有時候...
    雪山飛狐_91ae閱讀 4,728評論 10 36
  • 探索底層原理,積累從點滴做起。大家好,我是Mars。 往期回顧 iOS底層原理探索—OC對象的本質[https:/...
    勞模007_Mars閱讀 1,383評論 4 9
  • 上篇文章我們通過一個簡單的例子,講述了KVO的基本使用情況,下面我們來繼續(xù)深究KVO的本質是什么。 想要探究本質,...
    PerryMorning閱讀 494評論 0 2
  • 1、如果你給一個Person實例添加KVO,那么這個實例的的isa指針指向的是派生出來了NSKVONotifica...
    我真的不是張亮閱讀 509評論 0 0
  • 頭發(fā)和指甲長得慢了、青春期推遲、免疫力低下……你知道這些可能跟什么相關嗎?沒錯,這很有可能是因為缺乏蛋白質! 蛋白...
    紐扣媽咪閱讀 488評論 0 0

友情鏈接更多精彩內容