美文网首页
观察者模式-通知详解

观察者模式-通知详解

作者: 蜗牛非牛 | 来源:发表于2018-08-22 15:35 被阅读218次

    观察者模式也叫发布/订阅模式,是软件设计模式中的一种。在这种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
    观察者模式的类图如下:


    屏幕快照 2018-08-22 上午10.34.11.png

    可以看出它有四个角色,具体如下:

    抽象主题(Subject):抽象主题是一个协议,它是一个观察者的集合容器,定义添加观察者(attach)方法,移除观察者(detach)方法和所有观察者发送通知的方法(notifyObserve)。
    抽象观察者(Observe):抽象观察者也是一个协议,它有一个更新(update)方法。
    具体观察者(ConcreteObserve):观察协议具体实现。
    具体主题(ConcerteSubject):主题协议的具体实现。

    从图中可以看出,引入Observe和Subject这两个协议后,观察者模式可以完美的将观察者和被观察的对象分离开,不仅提高了系统的可复用行,还降低了耦合度。

    在Cocoa Touch框架中,观察者模式的具体应用有两个 - 通知(notification)机制和KVO(Key-ValueObserving)机制。

    通知机制

    通知机制与委托机制不同的是,前者是“一对多”的对象之间的通信,后者是“一对一”的对象之间的通信。

    在通知机制中对某个通知感兴趣的所有对象可以成为接收者首先,对这些对象需要向通知中心(NSNotificationCenter)发出addObserve:选择器:名称:对象消息进行注册,在投送对象投送通知给通知中新世,通知中心就会把通知广播给注册过的接收者。所有的接收者都不知道是谁投送的,更不关心细节。投送对象与接收者是一对多的关系。接收者如果对通知不再关注,会给通知中心发出removeObserver:名称:对象:消息解除注册,以后不再接收通知。


    屏幕快照 2018-08-22 上午11.31.38.png

    注册通知:

    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor whiteColor];
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(resignNotification:) name:@"login" object:nil];
    
        /** 换种方式 */
        __weak typeof(self) weakSelf = self;
        [[NSNotificationCenter defaultCenter]addObserverForName:@"drain" object:nil queue:[NSOperationQueue new] usingBlock:^(NSNotification * _Nonnull note) {
            NSLog(@"你瞅啥");
            NSLog(@"接收到通知:%@",[NSThread currentThread]);
        }];
    }
    
    -(void)resignNotification:(NSNotification *)notification{
        NSLog(@"%s",__func__);
        NSLog(@"接收到通知:%@",[NSThread currentThread]);
    }
    

    发送同步通知:

    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
         [[NSNotificationCenter defaultCenter]postNotificationName:@"login" object:nil userInfo:@{}];
    
    }
    

    发送异步通知:

    /**
     * NSPostingStyle有三种:
     NSPostNow:与postNotificationName相同(就是在哪个线程里面就是获取当前线程的通知队列并且默认采用NSPostNow发送时机)
     NSPostASAP:不立即发出通知,而是在runloop匹配时调用,即:runloop处理事件源时
     NSPostWhenIdle:runloop闲置的时候post,即:runloop进入睡眠时
     */
    /*
     NSNotificationCoalescing消息合并的方式
     NSNotificationNoCoalescing = 0, //不合并
     NSNotificationCoalescingOnName = 1,//按名称合并
     NSNotificationCoalescingOnSender = 2,//按发送者合并
     */
    -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
        //每个线程都默认又一个通知队列,可以直接获取,也可以alloc
        NSNotificationQueue *notificationQueue = [NSNotificationQueue defaultQueue];
        NSNotification *notification = [NSNotification notificationWithName:@"drain" object:nil];
        NSNotification * notificationtwo = [NSNotification notificationWithName:@"drain" object:nil];
    
        NSLog(@"发送通知before:%@",[NSThread currentThread]);
        [notificationQueue enqueueNotification:notification postingStyle:NSPostNow coalesceMask:NSNotificationNoCoalescing forModes:nil];
        [notificationQueue enqueueNotification:notificationtwo postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
        [notificationQueue enqueueNotification:notification postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
        NSLog(@"发送通知After:%@",[NSThread currentThread]);
    }
    

    移除通知:

    [[NSNotificationCenter defaultCenter]removeObserver:self name:@"login" object:nil];
    //<# #>就是<## >
    

    输出结果:

    2018-08-22 15:20:53.382286+0800 AngelClient[4074:168069] -[ViewController resignNotification:]
    2018-08-22 15:20:53.382421+0800 AngelClient[4074:168069] 接收到通知:<NSThread: 0x60c0000788c0>{number = 1, name = main}
    2018-08-22 15:20:53.382513+0800 AngelClient[4074:168069] 发送通知before:<NSThread: 0x60c0000788c0>{number = 1, name = main}
    2018-08-22 15:20:53.382889+0800 AngelClient[4074:168112] 你瞅啥
    2018-08-22 15:20:53.383015+0800 AngelClient[4074:168112] 接收到通知:<NSThread: 0x604000267dc0>{number = 3, name = (null)}
    2018-08-22 15:20:53.383172+0800 AngelClient[4074:168069] 发送通知After:<NSThread: 0x60c0000788c0>{number = 1, name = main}
    2018-08-22 15:20:53.383594+0800 AngelClient[4074:168112] 你瞅啥
    2018-08-22 15:20:53.383741+0800 AngelClient[4074:168112] 接收到通知:<NSThread: 0x604000267dc0>{number = 3, name = (null)}
    

    NSNotificationCenter是单例模式,创建获得共享实例的方法defaultCenter。其中名称是通知的名字,对象是投送通知时传递过来的对象(不一定是self对象,如果接收者不需要,可以将其设为nil ),USERINFO是投送通知时定义的字典对象,可以用于参数的传递,进行的是同步发送.NSNotificationQueue是将发送的通知加到当前线程的队列中,进行异步发送。
    下一篇:观察者模式-KVO详解

    相关文章

      网友评论

          本文标题:观察者模式-通知详解

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