美文网首页
监测那些常规方法捕捉不到的变化-观察者模式

监测那些常规方法捕捉不到的变化-观察者模式

作者: Leewins | 来源:发表于2017-10-31 09:08 被阅读37次

一、你可能遇到过的问题

Question 1.使用UITextField时;

当你想时时监测textField.text的变化,以获取最新的text,你是用这样的代理方法吗?

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    
    if (textField == self.textField) {
        NSString *futureStr = [NSString stringWithFormat:@"%@%@", textField.text, string];
        if ([futureStr isEqualToString:@"000"]) {
            NSLog(@"----------The text value is 000----------");
        }
    }
    return YES;
}

Question 2.使用UIWebView或WKWebView时;

由于网页端用Ajax,导致我们并不能用常规的网页加载代理方法来检测webView的title的值~比如这样

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {

    if (webView.title.length > 0) {
        self.title = webView.title;
    }
}

二、这里我们就需要用上观察者模式了

KVO,即key-value-observing,利用一个key来找到某个属性并监听其值得改变。其实这也是一种典型的观察者模式。

  • 1,添加观察者
  • 2,在观察者中实现监听方法,observeValueForKeyPath: ofObject: change: context:(因为这个方法属于NSObject,所以,可以用于检测任何对象的任何属性的变化)
  • 3,移除观察者
/**
 用万能的User类来煮个栗子~
 */
- (void)addObserverForUserName {
    
    User *user = [[User alloc] init];
    
    /* Whether the change dictionaries sent in notifications
     should contain NSKeyValueChangeNewKey and NSKeyValueChangeOldKey entries, respectively.
     -------------------------------------------------------------
     NSKeyValueObservingOptionNew = 0x01,新值
     NSKeyValueObservingOptionOld = 0x02,旧值
     */
    [user addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
}

/**
 监测 user 的 name 属性 发生变化的情况

 @param keyPath 被监听的属性
 @param object 被监听的对象
 @param change 新值和旧值
 @param context 附加的额外数据
 */
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSKeyValueChangeKey,id> *)change
                       context:(void *)context {

    if ([keyPath isEqualToString:@"name"] && [object isEqual:user]) {
        // Do Something
        NSLog(@"----------user'name has changed----------");
    }
}

- (void)dealloc {

    [user removeObserver:self forKeyPath:@"name"];
}

三、解决上述及类似的问题

Answer 1

[self.textField addTarget:self action:@selector(textFieldDidChange:) 
forControlEvents:UIControlEventEditingChanged];

- (void)textFieldDidChange:(UITextField *)textField {
    // TODO
    if ([textField.text isEqualToString:@"000"]) {
            NSLog(@"----------The text value is 000----------");
    }
}

Answer 2

/**
 为webView配置监听者
 */
- (void)configWebViewObserver {
    
    [webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];
    [webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSKeyValueChangeKey,id> *)change
                       context:(void *)context {
    
    if ([keyPath isEqualToString:@"title"] && [object isEqual:webView]) {
        self.title = self.webView.title;
    } else if ([keyPath isEqualToString:@"estimatedProgress"] && [object isEqual:webView]) {
        self.progressView.progress = self.webView.estimatedProgress;
    }
}

- (void)dealloc {
    
    [self.webView removeObserver:self forKeyPath:@"title"];
    [self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
}

附:再来一发监听UITableView的contentOffset

- (void)configObserverForTableView {
    
    [tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary<NSString *,id> *)change
                       context:(void *)context {
    
    if ([keyPath isEqualToString:@"contentOffset"] && object == tableView) {
        
        CGFloat offsetY             = self.contentOffset.y;
        CGFloat offsetX             = self.contentOffset.x;
        NSLog(@"----------offsetX = %f, offsetY = %f----------", offsetX, offsetY);
    }
}

- (void)dealloc {
    
    [tableView removeObserver:self forKeyPath:@"contentOffset"];
}

看到这里大家一定就能明白观察者模式的基本套路了吧,心里突然响起了音乐:"其实很简单,其实很自然"~

四、写在最后

  • 此方法可用于监听一切对象的属性变化,包括系统的类(UITableView、UIWebView等)和自定义的类(User、Car等)
  • 上面的User类是通例,属于基本模型,实际情况有需求而定
  • 还可以用于监听动画的特殊时刻,比如:frame、color等变化
  • 一定记得在析构函数里移除监听;
  • 一定记得在析构函数里移除监听;
  • 一定记得在析构函数里移除监听......
我是与文无关的图.JPG

相关文章

  • 监测那些常规方法捕捉不到的变化-观察者模式

    一、你可能遇到过的问题 Question 1.使用UITextField时; 当你想时时监测textField.t...

  • 刨根问底KVO原理

    介绍 KVO( NSKeyValueObserving )是一种监测对象属性值变化的观察者模式机制。其特点是无需事...

  • KVO,NSNotification,delegate及bloc

    KVO就是cocoa框架实现的观察者模式,一般同KVC搭配使用,通过KVO可以监测一个值得变化,比如View的高度...

  • NSNotification、Block、Delegate和KV

    KVO就是cocoa框架实现的观察者模式,一般同KVC搭配使用,通过KVO可以监测一个值的变化,比如View的高度...

  • iOS开发delegate、Block、KVC、KVO、NSNo

    KVO就是cocoa框架实现的观察者模式,一般同KVC搭配使用,通过KVO可以监测一个值的变化,比如View的高度...

  • KVO,NSNotification,delegate及bloc

    KVO观察者模式,一般同KVC搭配使用,通过KVO可以监测一个值的变化。是一对多的关系,一个值的变化会通知所有的观...

  • KVO使用和原理

    KVO是OC中观察者模式的一种实现,一个对象监测另一对象某属性是否发生变化,当被观察者某个属性发生改变时,会触发观...

  • Rxjava 初步学习使用

    一.原理学习 核心:观察者模式 观察者模式:A 对象(观察者)对 B 对象(被观察者)的某种变化高度敏感,需要在 ...

  • Observer模式(观察者模式)

    观察者模式(Observer Pattern):当观察对象的状态变化时,会自动通知给观察者。观察者模式属于行为型模...

  • 模板方法及观察者模式

    1、本文主要内容 模板方法定义 模板方法示例 观察者模式 本文主要讲两个设计模式,模板方法以及观察者模式,模板方法...

网友评论

      本文标题:监测那些常规方法捕捉不到的变化-观察者模式

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