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块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块 ...
随机推荐
- pgAdminIII使用图解
原文地址:http://www.2cto.com/database/201312/267218.html pgAdmin III简介 要打开一个到服务的连接,在树中选择所需的服务,并双击它,或使用“工 ...
- 《University Calculus》-chaper13-向量场中的积分-线积分
线积分: 基于二重积分和三重积分的引入,我们对于线积分的引入过程将会轻车熟路. 对于一根不均匀密度的铜丝,我们如何求其总质量?如下图. 类似二重积分和三重积分的引入,我们首先基于实际问题给出黎曼和的形 ...
- 【数学】【NOIp2012】同余方程 题解 以及 关于扩展欧几里得与同余方程
什么是GCD? GCD是最大公约数的简称(当然理解为我们伟大的党也未尝不可).在开头,我们先下几个定义: ①a|b表示a能整除b(a是b的约数) ②a mod b表示a-[a/b]b([a/b]在Pa ...
- 西安Uber优步司机奖励政策(1月18日~1月24日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- [置顶] android 图片库的封装
大家在做安卓应用的时候 经常要从网络中获取图片 都是通过URL去获取 可是如果本地有图片数据 从本地获取数据不更加快一些 自己在工作中遇到这个问题 所以采用了一个URL和本地图片的一个映射关系 ...
- 深度克隆---js对象引用
首先,我们要知道,javascript中除了基本类型(number,string,boolean,null,undefined)之外就是引用类型了,也可以说就是js对象了. 引用类型的赋值其实是对象保 ...
- swiper.js 移动端触摸滑动插件
API链接: http://www.swiper.com.cn/api/start/2014/1218/140.html <body> <div class="swiper ...
- 不可错过的手机APP常见8种界面导航样式
前言:相信每个移动开发project师都会遇到,当一个项目开发启动时,须要考虑搭建怎么的框架.一个好的框架.也会决定着一个APP的前途与命运.框架的风格,如今常见的有八种:标签导航.舵式导航.抽屉导航 ...
- 使用EPEL和REMI第三方yum源
http://dl.fedoraproject.org/pub/epel/ epel-release-latest-.noarch.rpm redhat5 epel-release-latest-.n ...
- 第二篇:智能电网(Smart Grid)中的数据工程与大数据案例分析
前言 上篇文章中讲到,在智能电网的控制与管理侧中,数据的分析和挖掘.可视化等工作属于核心环节.除此之外,二次侧中需要对数据进行采集,数据共享平台的搭建显然也涉及到数据的管理.那么在智能电网领域中,数据 ...