zoukankan      html  css  js  c++  java
  • NSNotification,NSNotificationCenter的使用、iOS中五种对象间传值的方式

    学习内容

    欢迎关注我的iOS学习总结——每天学一点iOS:https://github.com/practiceqian/one-day-one-iOS-summary

    NSNitification与NotificationCenter(通知与通知中心)

    1. 通知的使用

      • [[NSNotificationCenter defaultCenter]addObserver:selfselector:@selector
         (noticeAction:) name:@"name" object:nil];
        

        注册观察者

      • NSNotification* notice = [NSNotification notificationWithName:@"name" object:nil userInfo:params];
        [[NSNotificationCenter defaultCenter]postNotification:notice];
        

        创建一个通知并发送

      • 观察者对象的注册一定要比通知的发送提前,否则的话会接收不到通知

    2. 通知和delegate的基本区别

      • 通知是允许多对多的,而delegate只能是一对一的
      • 通知的耦合度较低,发送方不需要知道通知方的任何情况,而delegate不行
      • 通知的效率比起delegate略差
    3. 通知是同步还是异步的?

      • postNotification:通知的发送总是会卡住当前线程,等待所有的observer对象执行(如果没有经过特殊处理,接收者对象的selector与postNotification在同一线程执行)完成后才会继续往下执行,所以是同步的
    4. 通知的移除

      • 在iOS9之前的版本中,如果对一个观察者对象在delloc之前之中没有从通知中心移除(remove)的话,会产生BAD_ACCESS野指针错误,导致crash
      • iOS9.0及以后的版本中不会造成crash
      • 原因:iOS9.0之前NSNotificationCenter持有的是observer的unsafe_uncertain指针,如果观察者对象已经被释放,但是没有从通知中心移除,那么postNotification方法会向观察者已经被回收的内存发送消息,就会造成野指针访问错误,iOS9.0以后,系统将unsafe_uncertain指针更改成了weak指针(对象回收,自动置nil),向nil发送消息不会差生任何问题(同时这里说明了oc是可以向nil发送消息的)
    5. 异步通知

      • [[NSNotificationQueue defaultQueue]enqueueNotification:notice postingStyle:NSPostASAP];
        ----------------------------------------------------------------------------------typedef NS_ENUM(NSUInteger, NSPostingStyle) {
        	//空闲发送通知 当运行循环处于等待或空闲状态时,发送通知,对于不重要的通知可以使用。
          NSPostWhenIdle = 1,
          //尽快发送通知 当前运行循环迭代完成时,通知将会被发送,有点类似没有延迟的定时器。
          NSPostASAP = 2,
          //和postNotification一样是同步通知
          NSPostNow = 3
        };
        
      • 三种枚举类型代表三种发送方式(异步/同步都可)

      • 同样的,异步发送通知的话还可以使用开启一个新的线程的方式

      • dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
          [[NSNotificationCenter defaultCenter]postNotification:notice];
        });
        
    6. 通知的合并(待完善)

      • [[NSNotificationQueue defaultQueue] enqueueNotification:notice postingStyle:NSPostASAP coalesceMask:NSNotificationNoCoalescing forModes:nil];
        -----------------------------------------------------------------------------------
        typedef NS_OPTIONS(NSUInteger, NSNotificationCoalescing) {
        	  // 不合成
            NSNotificationNoCoalescing = 0,  
          	// 根据NSNotification的name字段进行合成
            NSNotificationCoalescingOnName = 1,  
          	// 根据NSNotification的object字段进行合成
            NSNotificationCoalescingOnSender = 2  
        };
        
      • NSNotificationQueue除了有异步通知的能力之外,也能对当前队列的通知根据NSNotificationCoalescing类型进行合并,需要配合不同的NSRunLoopMode来进行

      • 通过合并通知我们可以用来保证相同的通知只被发送一次

    7. NSNotificationCenter实现原理

      • 通知中心用来管理通知的接收和发送,一开始将观察者注册到通知中心的通知调度表中,然后发送通知时利用标识符name和object识别出观察者,并调用相应的观察者方法,即传递消息(消息传递机制),如果是基于block创建的通知就调用NSNitification的block
    8. NSNotificationCenter使用block方式添加的观察者

      • - (id<NSObject>)addObserverForName:(NSString *)name
                                    object:(id)obj
                                     queue:(NSOperationQueue *)queue
                                usingBlock:(void (^)(NSNotification *note))block
        
        
      • addObserver使用一个现存的对象作为观察者(一般为self),而使用block方法会创建一个匿名的(id)对象作为观察者,这个匿名对象会在指定的队列上去执行block

      • 如果queue为nil,则消息是默认在post线程中同步处理,即通知的post与转发是在同一线程中,不为nil的话就会在我们指定的队列中执行

      • 如果一个给定的通知触发了多个观察者的block操作,则这些操作会在各自的Operation Queue中被并发执行。所以我们不能去假设操作的执行会按照添加观察者的顺序来执行

      • 这个方法会返回一个匿名的观察者对象,我们需要手动释放这个对象。

    iOS中对象间的五种传值方式(属性、代理、单例、Block、通知)

    1. 属性传值

      • 通过对象的公有属性进行传值
    2. 代理传值

      • 在委托方定义协议,协议中声明@required/@optional方法,声明一个代理属性,使用weak修饰符

      • 在代理方遵守协议,实现协议中的方法

      • 初始化委托对象,将委托对象的代理设置为self(代理对象自身)

      • 查看代理方是否实现了需要执行的选择子(SEL),如果实现了便开始执行

      • if ([self.delegate respondsToSelector:@selector(codeIOS)]) {
          // 让代理方执行协议中的方法
          [self.delegate SEL];
        }
        
      • 代理传值一般用于逆向传值,如:A控制器跳转到B控制器,B控制器为委托对象,A控制器为代理对象,B对象的代理为A对象,那么在B对象中可以传值给A对象,并在A对象中执行相应的方法

    3. 单例模式传值

      • 将一个类写成单例(常用dispatch_once),这样这个类就只含有全局唯一的实例,可以向整个程序提供实例
      • 如果一个类创建实例会耗费很多资源,那么可以将这个类写成单例类,节省alloc,init的时间
      • 在程序中如果多个类访问同一个变量,那么也可以将将该变量写入单例类中,调用起来更加方便
    4. 使用block代码块进行传值

      • 可以用于数据在多个对象间传递,网络请求的回调等

      • //在对象B中block作为方法参数
        - (void)getNextPage:(void (^)(BOOL))completeBlock{
          //block可以嵌套,第一层block可以在最后的block体中进行回调
            [self getPage:self.page complete:^(NSMutableArray *result) {
                if ([result count]) {
                    self.page++;
                    [self.musicList addObjectsFromArray:result];
                    if (completeBlock) {
                      //需要回调时,执行block
                        completeBlock(true);
                    }
                }else{
                    if (completeBlock) {
                        completeBlock(false);
                    }
                }
            }];
        }
        ------------------------------------------------------------------------------
        //在对象A中isSucceed为回调回来的值
          [strongSelf.musicModel getNextPage:^(BOOL isSucceed) {
            if (isSucceed) {
              [strongSelf.waterFallCollectionView reloadData];
            }
          }];
        
    5. 通知传值

      • NSNotification的使用就是通知传值的一些用法
  • 相关阅读:
    js本地时钟
    《Real Time Rendering》第二章 图形渲染管线
    《Real Time Rendering》第三版 翻译
    《Windows via C/C++》学习笔记(一):Error handling
    《Real Time Rendering》第三章 图形处理单元
    《工程结构优化设计基础》总结
    《TCP/IP协议详解》学习笔记(一):概述
    【转载】四大开源3d游戏引擎探究
    几何非线性中的几个重要概念
    《Windows via C/C++》学习笔记(二):Working with Characters and String
  • 原文地址:https://www.cnblogs.com/chenprice/p/12852735.html
Copyright © 2011-2022 走看看