iOS开发——OC篇&消息传递机制(KVO/NOtification/Block/代理/Target-Action)
- KVO提供了这样一种机制:当对象中的某个属性值发生了改变,可以对这些值的观察者做出通知。KVO的实现包含在Foundation里面,基 于Foundation构建的许多Framework对KVO都有所依赖。要想了解更多关于如何使用KVO,可以阅读本期由Daniel写的的KVO和 KVC文章。
- 如果对某个对象中值的改变情况感兴趣,那么可以使用KVO消息传递机制。这里有两个要求,首先,接收者(会接收到值发生改变的消息)必须知道发 送者(值将发生改变的那个对象)。另外,接收者同样还需要知道发送者的生命周期,因为在销毁发送者对象之前,需要取消观察者的注册。如果这两个要求都满足 了,消息传递过程中可以是1对多(多个观察者可以注册某个对象中的值)。
- 如果计划在Core Data对象上使用KVO,需要知道这跟一般的KVO使用方法有点不同。那就是必须结合Core Data的故障机制(faulting mechanism),一旦core data出现了故障,它将会触发其属性对应的观察者(即使这些属性值没有发生改变)。
- 在不相关的两部分代码中要想进行消息传递,通知(notifacation)是非常好的一种机制,它可以对消息进行广播。特别是想要传递丰富的信息,并且不一定指望有谁对此消息关心。
- 通知可以用来发送任意的消息,甚至包含一个userInfo字典,或者是NSNotifacation的一个子类。通知的独特之处就在于发送者 和接收者双方并不需要相互知道。这样就可以在非常松耦合的模块间进行消息的传递。记住,这种消息传递机制是单向的,作为接收者是不可以回复消息的。
- 在苹果的Framework中,delegation模式被广泛的只用着。delegation允许我们定制某个对象的行为,并且可以收到某些 确定的事件。为了使用delegation模式,消息的发送者需要知道消息的接收者(delegate),反过来就不用了。这里的发送者和接收者是比较松 耦合的,因为发送者只知道它的delegate是遵循某个特定的协议。
- delegate协议可以定义任意的方法,因此你可以准确的定义出你所需要的类型。你可以用函数参数的形式来处理消息内容,delegate还 可以通过返回值的形式给发送者做出回应。如果只需要在相对接近的两个模块之间进行消息传递,那么Delegation是一种非常灵活和直接方式。
- 不过,过渡使用delegation也有一定的风险,如果两个对象的耦合程度比较紧密,相互之间不能独立存在,那么此时就没有必要使用 delegate协议了,针对这种情况,对象之间可以知道相互间的类型,进而直接进行消息传递。例如UICollectionViewLayout和 NSURLSessionConfiguration。
- Block相对来说,是一种比较新的技术,它首次出现是在OS X 10.6和iOS 4中。一般情况下,block可以满足用delegation实现的消息传递机制。不过这两种机制都有各自的需求和优势。
- 当不考虑使用block时,一般主要是考虑到block极易引起retain环。如果发送者需要reatain block,而又不能确保这个引用什么时候被nil,这样就会发生潜在的retain环。
- 假设我们想要实现一个table view,使用block替代delegate,来当做selection的回调,如下:
- self.myTableView.selectionHandler = ^void(NSIndexPath *selectedIndexPath) {
- // handle selection ...
- };
- 上面代码的问题在于self retain了table view,而table view为了之后能够使用block,进而 retain了block。而table view又不能把这个引用nil掉,因为它不知道什么时候不在需要这个block了。如果我们保证不了可以打破这个retain环,而我们又需要 retain发送者,此时block不是好的选择。
- NSOperation就可以很好的使用block,因为它能再某个时机打破retain环:
- self.queue = [[NSOperationQueue alloc] init];
- MyOperation *operation = [[MyOperation alloc] init];
- operation.completionBlock = ^{
- [self finishedOperation];
- };
- [self.queue addOperation:operation];
- 乍一看这似乎是一个retain环:self retain了queue,queue retain了operation,而operation retain了completion block,而completion blockretain了self。不过,在这里,将operation添加到queue时,会使operation在某个时机被执行,然后从queue 中remove掉(如果没有被执行,就会有大问题了)。一单queue移除了operation之后,retain环就被打破了。
- 再来一个示例:这里实现了一个视频编码器的类,里面有一个名为encodeWithCompletionHandler:的方法。为了避免出现retain环,我们需要确保编码器这个对象能够在某个时机nil掉其对block的引用。其内部代码如下所示:
- @interface Encoder ()
- @property (nonatomic, copy) void (^completionHandler)();
- @end
- @implementation Encoder
- - (void)encodeWithCompletionHandler:(void (^)())handler
- {
- self.completionHandler = handler;
- // do the asynchronous processing...
- }
- // This one will be called once the job is done
- - (void)finishedEncoding
- {
- self.completionHandler();
- self.completionHandler = nil; // <- Don't forget this!
- }
- @end
- 在上面的代码中,一旦编码任务完成,就会调用complietion block,进而把引用nil掉。
- 如果我们发送的消息属于一次性的(具体到某个方法的调用),由于这样可以打破潜在的retain环,那么使用block是非常不错的选择。另 外,如果为了让代码可读性更强,更有连贯性,那最好是使用block了。根据这个思路,block经常可以用于completion handler、error handler等。
- Target-Action主要被用于响应用户界面事件时所需要传递的消息中。iOS中的UIControl和Mac中的 NSControl/NSCell都支持这种机制。Target-Action在消息的发送者和接收者之间建立了一个非常松散耦合。消息的接收者不知道发 送者,甚至消息的发送者不需要预先知道消息的接收者。如果target是nil,action会在响应链(responder chain)中被传递,知道找到某个能够响应该aciton的对象。在iOS中,每个控件都能关联多个target-action。
- 基于target-action消息传递的机制有一个局限就是发送的消息不能携带自定义的payload。在Mac的action方法中,接收 者总是被放在第一个参数中。而在iOS中,可以选择性的将发送者和和触发action的事件作为参数。除此之外,没有别的办法可以对发送action消息 内容做控制。
- 根据上面讨论的结果,这里我画了一个流程图,来帮助我们何时使用什么消息传递机制做出更好的决定。忠告:流程图中的建议并非最终的答案;可能还有别的选项依然能实现目的。只不过大多数情况下此图可以引导你做出正确的决定。
- 上图中,还有一些细节需要做更近一步的解释:
- 上图中的有个盒子这样说到:sender is KVO compliant(发送者支持compliant)。这不仅以意味着当值发生改变时,发送者会发送KVO通知,并且观察者还需要知道发送者的生命周期。 如果发送者被存储在一个weak属性中,那么发送者有可能被nil掉,进而引起观察者发生leak。
- 另外底部的一个盒子说到:message is direct response to method call(消息直接在方法的调用代码中响应)。也就是说处理消息的代码跟方法的调用代码处于相同的地方。
- 最后,在左下角,处于一个决策问题的判断状态:sender can guarantee to nil out reference to block?(发送者能够确保nil掉到block的引用吗?),这实际上涉及到之前我们讨论到基于block 的APIs已经潜在的retain环。使用block时,如果发送者不能保证在某个实际能够把对block的引用nil掉,那么将会遇到retain环的 问题。





- 首次接触这些机制,感觉它们都能用于两个对象间的消息传递。但是仔细琢磨一番,会发现它们各自有其需求和功能。
iOS开发——OC篇&消息传递机制(KVO/NOtification/Block/代理/Target-Action)的更多相关文章
- iOS开发——OC篇&常用关键字的使用与区别
copy,assign,strong,retain,weak,readonly,readwrite,nonatomic,atomic,unsafe_unretained的使用与区别 最近在学习iOS的 ...
- iOS开发——OC篇&OC高级语法
iOS开发高级语法之分类,拓展,协议,代码块详解 一:分类 什么是分类Category? 分类就是类的补充和扩展部分 补充和扩展的每个部分就是分类 分类本质上是类的一部分 分类的定义 分类也是以代码的 ...
- iOS开发——OC篇&纯代码退出键盘
关于iOS开发中键盘的退出,其实方法有很多中,而且笔者也也学会了不少,包括各种非纯代码界面的退出. 但是最近开始着手项目的时候却闷了,因为太多了,笔者确实知道有很多中方法能实现,而且令我影响最深的就是 ...
- iOS开发——OC篇&协议篇/NSCoder/NSCoding/NSCoping
协议篇/NSCoder/NSCoding/NSCoping 协议声明类需要实现的的方法,为不同的类提供公用方法,一个类可以有多个协议,但只能有一个父类,即单继承.它类似java中的接口. 正式协议(f ...
- iOS开发——OC篇&特殊数据类型
一些特殊的数据类型 id.nil.Nil.SEL ,IMP Objective-C中有一些很有趣的数据类型经常会被错误地理解.他们中的大多数都可以在/usr/include/objc/objc.h或者 ...
- iOS开发UI篇—UITableviewcell的性能优化和缓存机制
iOS开发UI篇—UITableviewcell的性能问题 一.UITableviewcell的一些介绍 UITableView的每一行都是一个UITableViewCell,通过dataSource ...
- iOS开发——UI篇OC篇&UIDynamic详解
iOS开发拓展篇—UIDynamic(简单介绍) 一.简单介绍 1.什么是UIDynamic UIDynamic是从iOS 7开始引入的一种新技术,隶属于UIKit框架 可以认为是一种物理引擎,能模拟 ...
- iOS开发UI篇—从代码的逐步优化看MVC
iOS开发UI篇—从代码的逐步优化看MVC 一.要求 要求完成下面一个小的应用程序. 二.一步步对代码进行优化 注意:在开发过程中,优化的过程是一步一步进行的.(如果一个人要吃五个包子才能吃饱,那么他 ...
- iOS开发多线程篇—线程安全
iOS开发多线程篇—线程安全 一.多线程的安全隐患 资源共享 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块 ...
随机推荐
- 那些年我用awk时踩过的坑——awk使用注意事项
由于项目经历原因,经常使用awk处理一些文本数据.甚至,我特意下载了一个windows上的awk:gawk.exe,这样在windows上也能享受awk处理数据的方便性,. 俗话说,"常在河 ...
- Spring 配置中的 default-lazy-init属性
spring的容器是提供了lazy-load的,即默认的缺省设置是bean没有lazy-load,该属性处于false状态,这样导致spring在启动过程导致在启动时候,会默认加载整个对象实例图,从初 ...
- Rocketmq整体分析
之前本人在实际的生产环境中,使用过activemq和rabbitmq消息队列,在使用过程中出现一些难以解决的问题,本文通过产品选型.网络架构和核心特性分析了rocketmq的优势和特性. 产品选型 我 ...
- 输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的和的最大值。要求时间复杂度为O(n)
群里看到这道题,用python做了做, def find(array): v_sum = greatest = 0 for a in array: v_sum += a v_sum = 0 if v_ ...
- Axure7.0.0.3155注册码
Licence:aaa Key1:h624pifAqt7It5e8boKkML+Y4RjDX5xknP4k7QktJYQoxsvv7VUS7hBCv/2ef45P Key2:2GQrt5XHYY7SB ...
- mysql编码和Java编码相应一览表
MySQL to Java Encoding Name Translations MySQL Character Set Name Java-Style Character Encoding Name ...
- [转] C语言多维数组与多级指针
http://c.biancheng.net/cpp/html/477.html 多维数组与多级指针也是初学者感觉迷糊的一个地方.超过二维的数组和超过二级的指针其实并不多用.如果能弄明白二维数组与二级 ...
- 手把手教你从 Core Data 迁移到 Realm
前言 看了这篇文章的标题,也许有些人还不知道Realm是什么,那么我先简单介绍一下这个新生的数据库.号称是用来替代SQLite 和 Core Data的.Realm有以下优点: 使用方便 Realm并 ...
- NYOJ-520 最大素因子
这个题基本上就两个知识点, 一个素数筛选法求素数,另一个是求最大公因子, 不过确定最大素数在素数表中的位置时,要用到二分的思想,不然会超时,下面是具体代码的实现; #include <stdio ...
- codevs 1282 约瑟夫问题(线段树)
#include<iostream> #include<cstdio> #include<cstring> #define maxn 30010 using nam ...