开发过程中该选择Blocks还是Delegates

   一般在这种情况下,我喜欢问我自己:“如果问题交给Apple,他会怎么做呢?”当然,我们都知道Apple肯定知道怎么做,因为从某一层面上看,Apple的文档就是一本用来指导我们如何使用设计模式的指导书。

  因此我们需要去研究一下Apple分别是在什么情况下使用delegate和block,如果我们发现了Apple做这种选择的套路,我们就可以构建出一些规则,可以帮助在我们在自己的代码中做相同选择。

  要找出Apple使用delegate的场景很简单,我们只要搜索官方文档中的“delegate”,就会获取到很多使用delegation的类。

  但是搜索Apple中有关使用blocks的文档就有点困难了,因为我们不能直接搜索文档中的“^” 。然而,Apple声明方法时有很好的命名习惯(这也是我们精通iOS开发的一项必备技能)。例如:一个以NSString为参数的方法,方法的selector就会有String字眼,像initWithString;dateFromString;StartSpeaingString。

  当Apple的方法使用block,这个方法将会有“Handler”,“Completion”或者简单的“Block”作为selector;因此我们可以在标准的iOS API文档中搜索这些关键词,用以构建一个可信任的block用例列表。

  1.大多数delegate protocols 都拥有几个消息源。

  以我正在看的GKMatch为例(A GKMatch object provides a peer-to-peer network between a group of devices that are connected to Game Center,是iOS API中用来提供一组设备连接到Game Center点对点网络的对象)。从这个类中可以看到消息的来源分别是:当从其他玩家那接收到数据、当玩家切换了状态、当发生错误或者当一个玩家应该被重新邀请。这些都是不同的事件。如果Apple在这里使用block,那么可能会有以下两种解决方式:

  可以对应每一个事件注册相应的block,显然这种方式是不合理的。( If someone writes a class that does this in Objective-C, they are probably an asshole.)

  创建一个可以接受任何可能输入的block

  1

  void (^matchBlock)(GKMatchEvent eventType, Player *player, NSData *data, NSError *err);

  很明显这种方式既不简便又不易读,所以你可能从未看过这样的解决方案。如果你看过这样的解决方式,但是这显然是一个糟糕至极的代码行,你不会有精力去维护这个。

  因此,我们可以得出一个结论:如果对象有超过一个以上不同的事件源,使用delegation。

  2.一个对象只能有一个delegate

  由于一个对象只能有一个delegate,而且它只能与这个delegate通信。让我们看看CLLocationManager 这个类,当发现地理位置后,location manager 只会通知一个对象(有且只有一个)。当然,如果我们需要更多的对象去知道这个更新,我们最好创建其他的location manager。

  这里有的人可能想到,如果CLLocationManager是个单例呢?如果我们不能创建CLLocationManager的其他实例,就必须不断地切换delegate指针到需要地理数据的对象上(或者创建一个只有你理解的精密的广播系统)。因此,这样看起来,delegatetion在单例上没有多大意义。

  关于这点,最好的印证例子就是UIAccelerometer。在早期版本的iOS中,单例的 accelerometer 实例有一个delegate,导致我们必须偶尔切换一下。这个愚蠢的问题在之后的IOS版本被修改了,现在,任意一个对象都可以访问CMMotionManager block,而不需要阻止其他的对象来接收更新。

  因此,我们可以得出另一个结论:“如果一个对象是单例,不要使用delegation”。

  3.一般的delegate方法会有返回值

  如果你观察一些delegate方法(几乎所有的dataSource方法)都有一个返回值。这就意味着delegating对象在请求某些东西的state(对象的值,或者对象本身),而一个block则可以合理地包含state或者至少是推断state,因此block真正是对象的一个属性。

  让我们思考一下一个有趣的场景,如果向一个block提问:“What do you think about Bob?”。block可能会做两件事情:发送一个消息去捕获对象并询问这个对象怎么看待Bob,或者直接返回一个捕获的值。如果返回了一个对象的响应,我们应该越过这个block直接获取这个对象。如果它返回了一个捕获的值,那么这应该是一个对象的属性。

  从以上的观察,我们可以得出结论:如果对象的请求带有附加信息,更应该使用delegation

  4.过程 vs 结果(Process vs. Results)

  如果查看NSURLConnectionDelegate 以及 NSURLConnectionDataDelegate,我们在可以protocol中看到这样的消息:我将要做什么(如: willSendRequest,将要发送请求)、到目前为止我知道的信息(如:canAuthenticateAgainstProtectionSpace)、我已经完成这些啦( didReceiveResponse,收到请求的回复,即完成请求)。这些消息组成一个流程,而那些对流程感兴趣的delegate将会在每一步得到相应的通知。

  当我们观察handler和完整的方法时,我们发现一个block包含一个响应对象和一个错误对象。显然这里没有任何有关“我在哪里,我正在做什么的”的交互。

  因此我们可以这样认为,delegate的回调更多的面向过程,而block则是面向结果的。如果你需要得到一条多步进程的通知,你应该使用delegation。而当你只是希望得到你请求的信息(或者获取信息时的错误提示),你应该使用block。(如果你结合之前的3个结论,你会发现delegate可以在所有事件中维持state,而多个独立的block确不能)

  从上面我们可以得出两个关键点。首先,如果你使用block去请求一个可能失败的请求,你应当只使用一个block。我们可以看到如下的代码:

  [fetcher makeRequest:^(id result) {

  // do something with result

  } error:^(NSError *err) {

  // Do something with error

  }];

  上面代码的可读性明显比下面block的可读性差(作者说这个是他不谦虚的观点,其实个人认为没有那么严重)

  [fetcher makeRequest:^(id result, NSError *err) {

  if(!err) {

  // handle result

  } else {

  // handle error

  }

  }];

时间: 2024-12-29 00:27:26

开发过程中该选择Blocks还是Delegates的相关文章

iOS开发过程中专门在调试时运行代码的方法

在开发过程中,我们经常会使用NSLog用于跟踪调试,不过在发布的产品可能 并不希望这些调试代码被运行.这里有一个小技巧分享一下. 在编写代码时可以使用如下方式: #ifdef DEBUG< // Debug 模式的代码... #else< // Release 模式的代码... #endif 其中的DEBUG是在Xcode默认的工程中已经定义好的,也可以根据自己的实际情 况添加其他常量定义. 在Xcode中,选择导航区域左侧顶端的根节点,然后选择Project/Build Settings,在

快速原型开发模式在实际开发过程中的应用

[摘要]本文以作者的实践开发经验为主线,从理论和实际的角度探讨快速原型开发模式在实践开发中的应用,并从软件开发的各个角度.各个时期剖析快速开发模式的优缺点和应该注意的问题. [关键字]软件工程.开发模式.快速开发.软件开发.原型模式     快速原型开发模式的基本思想是在系统开发的初期,在对用户需求初步了解的基础之上,以快速的方法先构造一个可以工作的系统原型.将这个原型提供给用户使用,听取他们的意见.然后修正原型,补充新的数据.数据结构和应用模型,形成新的原型.经过几次迭代以后,可以达到用户与开

在C和C++开发过程中应用测试驱动开发的理念

测试驱动开发和现在流行敏捷开发的是分不开的,测试驱动开发是敏捷开发的一个强有力工具,可以帮助我们从简单的设计开始,逐步地有保护重构设计直至完善设计过程.测试驱动开发是 Kent 提出的一种新的软件开发流程,现在已广为人知,这种开发方法依赖于极短重复的开发周期,面对开发需求,http://www.aliyun.com/zixun/aggregation/7155.html">开发人员要先开发代码测试用例,这些代码实现的测试用例定义了工程要实现的需求, 然后去开发代码快速测试通过这这些用例,这

移动应用开发过程中的迭代式原型设计

主要结论 移动应用原型创建过程中采用迭代式快速开发方法的重要性. 可以从对手身上学到什么,如何从他们的失误中获益. 如何为你的应用定义USP,如何通过故事板(Storyboarding).用户场景和故事图(Story-mapping)为自己挑选出最理想的用户. 如何使用纸面原型匹配团队的预期,并专注于共享的最终交付成果. 如何使用原型工具收集.管理和验证需求,进而在无需进行太多文案工作的情况下让产品解决方案具象化. 根据Yahoo Flurry提供的数据,消费者使用手机的时间中有超过90%用于各

人工智能和大数据的开发过程中需要注意这12点

人工智能是近年来科技发展的重要方向,在大数据时代,对数据采集.挖掘.应用的技术越来越受到瞩目.在人工智能和大数据的开发过程中,有哪些特别需要注意的要点? 人工智能领域的算法大师.华盛顿大学教授Pedro Domingos对此进行了深入思考. 在我们新近翻译的<智能Web算法>(第2版)中,对Pedro Domingos教授的观点进行了高度的概括,提炼出12个注意点,为行业开发实践提供了重要参考: 注意点1:你的数据未必可靠 在实际应用中,有很多各种各样的原因会导致你的数据是不可靠的.因此,当你

photoshop教程:菜单栏中的选择命令

  photoshop软件的选择菜单栏中的命令主要是针对选区进行各种编辑,如创建.修改或存储选区等操作.下面系统之家小编就菜单栏中的选择命令作详细介绍.希望对photoshop的初学者们有所帮助. 一:全部命令 利用"全部"命令,可将当前视图全部选中. 二:取消选择命令 执行"取消选择"命令,将取消视图中的选区,若使用的是矩形选框工具.椭圆选框工具或套索工具,可在图像中单击选定区域外的任何位置,取消选择. 三:重新选择命令 使用"重新选择"命令可

基于IBM Rational Build Forge实现敏捷开发过程中的持续构建

在敏捷开发过程中,软件构建周期以及自动化程度直接影响开发的速度和质量.本文结合具体的软件开发项目,描述如何利用 IBM Rational Build Forge 在敏捷开发过程中实现完全自动化的软件构建,产品安装以及单元测试,进行每天持续快速构建,提高开发团队的效率,改进产品和开发质量. 概述 敏捷开发(Agile development)是一种以人为核心.迭代.循序渐进的开发方法,开发周期一般是两星期到四星期.敏捷开发的一大原则是尽早的.持续的交付有价值的软件来使客户满意,交付的间隔时间越短越

SQL Server开发过程中常见问题总结

在SQL Server开发问题中你可能会问到的十个问题: 1.什么是常见的对表和字段的名字约束? 2.有没有可能在不了解T-SQL的情况下编写存储过程? 3.T-SQL中如何比较CLR存储过程和函数的性能? 4.我如何在一个存储过程中使用另一个存储过程产生的结果? 5.我如何解决SQL Server 2005的并发问题? 6.在SQL Server 2005中用什么工具替代了查询分析器? 7.你能提供一些有关SQL和T-SQL的详细信息吗? 8.SQL Server 2005有没有新的索引类型?

在word2007中合适选择链接和插入

     当要在word2007中使用其他程序中的数据时,有两种选择:链接或嵌入.事实上,尽管使用的术语不同,但是含义是相似的.例如,将图片插入到 word2007文档中时可以使用这些选项.定位到图片后,利用"插入"按钮的下拉箭头从"插入"."链接到文件"和"插入和链接"中进行选择."链接" 的意思很明显,通过它插入的内容仍然以某种方式与原来的应用程序或文件相连."插入"可能不够明确,可