KVO

作者: 周二可 | 来源:发表于2018-04-08 11:30 被阅读6次

    原理

    当你观察一个对象时,一个新的类会动态被创建。这个类继承自该对象的原本的类,并重写了被观察属性的 setter 方法。自然,重写的 setter 方法会负责在调用原 setter方法之前和之后,通过调willChangeValueForKey: 和 didChangevlueForKey:这两个方法来通知所有观察对象值的更改。最后把这个对象的 isa 指针 指向这个新创建的子类,对象就神奇的变成了新创建的子类的实例。不仅如此,Apple 还重写了 -class 方法,企图欺骗我们这个类没有变,就是原本那个类。

    原理

    1.使用姿势 http://zhangbuhuai.com/understanding-kvo/

    • 监听的时候传入上下文来区分
    • 移除的时候根据上下文来移除
    • 为了避免取消订阅时造成的crash,可以把取消订阅代码放在@try-@catch语句中
    static void * zwContentSize = &zwContentSize;
        
    - (void)viewDidLoad {
        
        [super viewDidLoad];
        
        // 1. subscribe
        [_tableView addObserver:self
                     forKeyPath:NSStringFromSelector(@selector(contentSize))
                        options:NSKeyValueObservingOptionNew
                        context:zwContentSize];
    }
        
    // 2. responding
    - (void)observeValueForKeyPath:(NSString *)keyPath
                          ofObject:(id)object
                            change:(NSDictionary *)change
                           context:(void *)context {
        if (context == zwContentSize) {
            // configure view
        } else {
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
        
    - (void)dealloc {
        @try {
            // 3. unsubscribe
            [_tableView removeObserver:self
                            forKeyPath:NSStringFromSelector(@selector(contentSize))
                               context:zwContentSize];
        }
        @catch (NSException *exception) {
            
        }
    }
    

    2.如何自己实现KVO http://tech.glowing.com/cn/implement-kvo/

    3.手动设定KVO https://yq.aliyun.com/articles/30483

    如果将一个对象设定成属性,这个属性是自动支持KVO的,如果这个对象是一个实例变量,那么,这个KVO是需要我们自己来实现的

    //
    //  Student.m
    //  SuperNotification
    //
    //  Copyright (c) 2014年 Y.X. All rights reserved.
    //
    
    #import "Student.h"
    
    @implementation Student
    
    @synthesize name = _name;
    - (void)setName:(NSString *)name
    {
        _name = name;
    }
    - (NSString *)name
    {
        return _name;
    }
    
    
    // 手动设定KVO
    - (void)setAge:(NSString *)age
    {
        [self willChangeValueForKey:@"age"];
        _age = age;
        [self didChangeValueForKey:@"age"];
    }
    - (NSString *)age
    {
        return _age;
    }
    
    // 该方法来告诉系统是否监听某个key
    + (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key
    {
        // 如果监测到键值为age,则指定为非自动监听对象
        if ([key isEqualToString:@"age"])
        {
            return NO;
        }
        
        return [super automaticallyNotifiesObserversForKey:key];
    }
    
    @end
    

    相关文章

      网友评论

        本文标题:KVO

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