zoukankan      html  css  js  c++  java
  • NSNotification系统通知优化

    最近在github上看到了LRNotificationObserver这个项目,看了一下实现方式,作者通过ARC机制实例化注册对象子类与关联对象的方法来管理注册对象的生命周期。从而省去了系统通知移除的过程,本篇介绍该项目实现过程。

    NSNotificationCenter 通知存在的问题

    注册

    [[NSNotificationCenter defaultCenter] addObserver:anObserver
                                             selector:@selector(handleNotification:)
                                                 name:aNotificationName
                                               object:anObjectThatFiresTheNotification];

    移除

    [[NSNotificationCenter defaultCenter] removeObserver:anObserver
                                                    name:aNotificationName
                                                  object:anObjectThatFiresTheNotification];

    这是正常使用通知的情形,这样使用存在两个问题

    • 每次使用都需要手动移除观察者。
    • 如果在主线程注册观察者然后在线程B中发送通知,如果通知事件是更新UI那么就会出现问题因为此时是在线程B操作而不是主线程。

    LRNotificationObserver

    LRNotificationObserver对象的内部持有NSNotificationCenter对象实际上是对NSNotificationCenter基础功能进一步的封装。

    LRNotificationObserver自动管理观察者

    LRNotificationObserver有两种方法初始化

    • 实例化注册对象
    @property (nonatomic, strong) LRNotificationObserver *backgroundObserver;
    
    self.backgroundObserver = [LRNotificationObserver observerForName:UIApplicationDidEnterBackgroundNotification
                                                                block:^(NSNotification *note) {
                                                                    // Do appropriate background task
                                                                }];

    这种方法需要声明一个LRNotificationObserver对象作为属性,根据ARC内存管理当对象销毁时对象的属性也会一起销毁
    这种情况下作者把销毁的方法写在了LRNotificationObserver对象的dealloc方法中。

    - (void)dealloc
    {
        [self stopObserving];
    }
    - (void)stopObserving
    {
        [_notificationCenter removeObserver:self name:_name object:_object];
        [self clear];
    }
    - (void)clear
    {
        _block = nil;
        _targetAction = nil;
        _operationQueue = nil;
        _dispatchQueue = nil;
    }
    • 使用类方法不用实例化对象
    [LRNotificationObserver observeName:UIApplicationDidReceiveMemoryWarningNotification
                                  owner:self
                                  block:^(NSNotification *note) {
                                      // Purge unnecessary cache
                                  }];

    虽然不用实例化LRNotificationObserver但是要传入owner参数,owner相当于一个钩子,让其与LRNotificationObserver对象进行关联。

    + (void)addObserver:(LRNotificationObserver *)observer asPropertyOfOwner:(id)owner
    {
        objc_setAssociatedObject(owner, (__bridge void *)observer, observer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }

    通过运行时关联对象的方法将LRNotificationObserver对象与owner对象关联,当owner销毁时关联断开,LRNotificationObserver对象不被任何对象持有销毁。执行dealloc方法


    线程安全

    LRNotificationObserver可以指定通知方法执行队列

    [LRNotificationObserver observeName:@"someNotificationThatShouldUpdateTheUI"
                                 object:anObject
                                  owner:anOwner
                         dispatch_queue:dispatch_get_main_queue()
                                 target:viewController
                               selector:@selector(methodToBeExecutedOnMainThread:)];

    当收到通知后线程会自动切换到dispatch_queue置顶队列所在的线程中。

    - (void)executeNotificationFiredBlock:(dispatch_block_t)block
    {
        if (self.operationQueue)
        {
            if ([NSThread isMainThread] && self.operationQueue == [NSOperationQueue mainQueue])
            {
                block();
            }
            else
            {
                [self.operationQueue addOperationWithBlock:block];
            }
        }
        else if (self.dispatchQueue)
        {
            if ([NSThread isMainThread] && self.dispatchQueue == dispatch_get_main_queue())
            {
                block();
            }
            else
            {
                dispatch_async(self.dispatchQueue, block);
            }
        }
        else
        {
            block();
        }
    }

    作者通过是否指定dispatch_queueoperationQueue来判断是否切换队列,如果没有指定那么默认操作将在发送通知的线程中执行。

  • 相关阅读:
    测试平台系列(38) 接入github第三方登录(上)
    测试平台系列(37) 运用装饰器给用例加上执行日志
    测试平台系列(36) 使用全局变量
    测试平台系列(35) 编写全局变量管理页面
    OCP 063中文考试题库(cuug内部资料)第16题
    OCP 063中文考试题库(cuug内部资料)第15题
    D. Strange Housing 题解(思维+染色)
    B. Strange Definition 题解(质因子分解+思维)
    F. Euclid's nightmare 题解(MST+思维)
    D. Fragmentation merging 题解(思维)
  • 原文地址:https://www.cnblogs.com/itrena/p/5927088.html
Copyright © 2011-2022 走看看