• iOS设计模式之观察者模式


    观察者模式

    基本理解

    • 观察者模式又叫做发布-订阅(Publish/Subscribe)模式。
    • 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,是他们能够自动更新自己。
    • 观察者只从通知器(发行商)把自己注册到(订阅)特定的通知(杂志)。当有通知的时候,观察者从通知器得到它订阅的通知。

    观察者模式的特点

    将一个系统分割成一系列相互协作的类有一个很不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维护一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。
    而观察者的关键是有一个对象(Model),它可以有多个观察者,一旦对象的状态发生了变化,那么所有的观察者都可以得到通知,及时更新。

    使用场景

    • 当一个对象的改变需要同时改变其他对象的时候,我们就可以使用,而且不知道具体有多少个对象有待改变时,应该考虑使用观察者模式。
    • 观察者模式所做的工作就是在解除耦合。让耦合的双方都依赖于抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
    • 例如,当用户点击视图上的排序按钮时,事件会传递给控制器,让模型在后台对其数据进行排序。当模型成功执行了对数据的操作后,它会通知所有相关的控制器,让他们用到的数据更新其视图。

    在Cocoa Touch框架中使用观察者模式

    Cocoa Touch框架用两种技术改写了观察者模式--通知和键值观察(KVO)。尽管是两种不同的Cocoa技术,两者都实现了观察者模式。

    • 通知
      Cocoa Touch框架中使用NSNotificationCenter和NSNotification对象实现了一对多的发布订阅模型。一个中心对象为所有观察者提供变更通知,主要从广义上关注程序事件
    • 键值观察
      被观察的对象直接向观察者发送通知,绑定与特定对象属性的值。

    例子

    User.h

    //
    //  User.h
    //  ObserverDemo
    //
    //  Created by zhanggui on 15/8/6.
    //  Copyright (c) 2015年 zhanggui. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface User : NSObject
    {
        NSString *userName;
        NSString *userAge;
        NSString *userAddress;
    }
    @end
    

    User.m

    //
    //  User.m
    //  ObserverDemo
    //
    //  Created by zhanggui on 15/8/6.
    //  Copyright (c) 2015年 zhanggui. All rights reserved.
    //
    
    #import "User.h"
    
    @implementation User
    
    @end
    

    ViewController.m

    //
    //  ViewController.m
    //  ObserverDemo
    //
    //  Created by zhanggui on 15/8/6.
    //  Copyright (c) 2015年 zhanggui. All rights reserved.
    //
    
    #import "ViewController.h"
    #import "User.h"
    @interface ViewController ()
    {
        User *user1;
    }
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        user1 = [User new];
        [user1 setValue:@"zhangsan" forKey:@"userName"];
        //KVO
        [user1 addObserver:self forKeyPath:@"userName" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"I want to update name"];
        _nameLabel.text = [user1 valueForKey:@"userName"];
        
        
        //Notification
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeColor:) name:@"changeColor" object:nil];
    }
    -(void)dealloc {
        [user1 removeObserver:self forKeyPath:@"userName"];
    }
    #pragma mark - NotificationAction
    -(void)changeColor:(NSNotification *)notification
    {
        if ([notification.object isKindOfClass:[UIColor class]]) {
            self.view.backgroundColor = (UIColor *)notification.object;
        }
        NSLog(@"我收到通知了");
    }
    
    #pragma mark - ButtonAction
    - (IBAction)buttonAction:(id)sender {
        [user1 setValue:@"zhangqiang" forKey:@"userName"];
    }
    
    #pragma mark - ObserverMehtod
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
        if ([keyPath isEqualToString:@"userName"]) {
            _nameLabel.text = [user1 valueForKey:@"userName"];
        }
    }
    @end
    

    SecondViewController.m

    //
    //  SecondViewController.m
    //  ObserverDemo
    //
    //  Created by zhanggui on 15/8/6.
    //  Copyright (c) 2015年 zhanggui. All rights reserved.
    //
    
    #import "SecondViewController.h"
    
    @interface SecondViewController ()
    
    @end
    
    @implementation SecondViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
    }
    
    - (IBAction)changeColorAction:(id)sender {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"changeColor" object:[UIColor redColor]];
    }
    @end
    

    上述例子中分别使用了KVO和NSNotificationCenter来体现观察者模式。其中:

     [user1 addObserver:self forKeyPath:@"userName" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"I want to update name"];
    

    我们给user1添加观察者self,也就是ViewController。让它去观察user的userName属性,当有更新的时候就会调用:

    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
        if ([keyPath isEqualToString:@"userName"]) {
            _nameLabel.text = [user1 valueForKey:@"userName"];
        }
    }
    

    在这里来处理显示内容的更新。
    还有就是通过SecondViewController中点击一个按钮去改变ViewController的背景色,具体请看代码。

    附:

  • 相关阅读:
    CF 793 B (队列中的交换位置)
    WPF转换器
    WPF自定义控件指针仪表(依赖属性)
    面试可能会问到的问题
    返回局部变量是一个指向常量的字符串指针
    自定义c++二维动态数组
    1. 文件乱码 行远
    Nginx自启动脚本
    实验一密码引擎商用密码算法实现2交叉测试
    ARC117F Gateau
  • 原文地址:https://www.cnblogs.com/zhanggui/p/4707277.html
Copyright © 2020-2023  润新知