iOS--开发该选择Blocks还是Delegates

原文链接:http://blog.stablekernel.com/blocks-or-delegates/



有人问了我一个很棒的问题,我把这个问题总结为:“开发过程中该选择 blocks or 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。我们可以看到如下的代码:


1

2

3

4

5

[fetcher makeRequest:^(id result) {

   // do something with result

} error:^(NSError *err) {

    // Do something with error

}];

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


1

2

3

4

5

6

7

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

     if(!err) {

         // handle result

     else {

        // handle error

     }

}];

 

时间: 2024-10-03 13:46:17

iOS--开发该选择Blocks还是Delegates的相关文章

开发该选择Blocks还是Delegates

前文:网络上找了很多关于delegation和block的使用场景,发现没有很满意的解释,后来无意中在stablekernel找到了这篇文章,文中作者不仅仅是给出了解决方案,更值得我们深思的是作者独特的思考和解决问题的方式,因此将这篇文章翻译过来,和诸君探讨,翻译的很多地方不是很到位,望大家提出意见建议. 有人问了我一个很棒的问题,我把这个问题总结为:“开发过程中该选择 blocks or delegates?当我们需要实现回调的时候,使用哪一种方式比较合适呢?” 一般在这种情况下,我喜欢问我自

开发该选择Blocks还是Delegates(转)

原文链接:http://blog.stablekernel.com/blocks-or-delegates/ By Joe Conway,CEO | Jul 11,2013 11:29:00 AM 有人问了我一个很棒的问题,我把这个问题总结为:“开发过程中该选择 blocks or delegates?当我们需要实现回调的时候,使用哪一种方式比较合适呢?” 一般在这种情况下,我喜欢问我自己:“如果问题交给Apple,他会怎么做呢?”当然,我们都知道Apple肯定知道怎么做,因为从某一层面上看,A

iOS开发-照片选择

本来想做个注册登录的表单的,想想还是先做个简单的头像选择,一般情况下不管是内部管理系统还是面向公众的互联网公司,注册登录是免不了的,用户头像上传是免不了的,尤其是企业用户,上传了自己的图片才感觉自己买的系统是比较值的.iOS开发中上传图片还是比较简单的,通过UIImagePickerController和协议就很容易的实现的图片的选择和上传. 页面布局 首先看下视图,一个按钮,一个标签和一个ImageView: 界面很简单,头文件中声明一下UIImageView: @property (weak

iOS 开发图片资源选择png格式还是jpg格式

对于iOS本地应用程序来说最简单的答案就是始终使用PNG,除非你有非常非常好的理由不用它. 当iOS应用构建的时候,Xcode会通过一种方式优化.png文件而不会优化其它文件格式.它优化得相当的好 他们之间有以下区别: 1.同个分辨率的图片,保存为png要比jpg大: 2.png图片有alpha通道,因此它支持图片透明,这点在ios开发中尤为重要:而jpg不支持透明 3.xcode会对png格式进行特殊的优化处理,而对于其他图片不做处理 总结一下有以下几点: 1.如果你的图片都是xcode本地就

iOS开发-数据选择UIPickerView

UIPickerView开发一般选择区域或者分级数据的时候会使用到,类似于前端中用到树状结构,不过PC上一般都是从上到下的分级,使用UIPickView是从左到右实现,可以动态的设置UIPickView中中行列数据,将结果显示在文本输入框里,简单的定义一下数据源.通过声明协议捕获事件,展示结果,比较简单,进入正题. 页面布局 页面布局比较简单,一个UIPickerView,一个文本框: 头文件中的声明,实现了UIPickerViewDelegate,UIPickerViewDataSource协

ios开发-教程选择

旧项目为oc项目 入门选择书籍 he.iOS.Apprentice 图文教程 只能看 The.iOS.Apprentice.2nd.Edition 之后都是swift介绍了 共五个教程 分张介绍 阅读教程参考了有道翻译... The iOS Apprentice 1 - Getting Started 一个名字为<The Bull's Eye game>的游戏介绍 1.学习了xCode的简单布局 2.Oc工程建立和结构 3.Main.storyboard中如何添加Button,Label,和绑

iOS开发--日期选择

展示效果 : (UIDatePicker & UIToolBar & UITextField 共同配合使用) 请问 : 实现的步骤是什么 ? 第一步,在程序视图加载完成之后,首先来创建一个 "日期选择器" 并将 "日期选择器" 设置为文本框的 "输入视图". 完成后再创建一个 "工具栏", 设置背景颜色及frame. 最后将 "工具栏" 设置为文本框的辅助输入视图. 特别注意 : 如果要将一

做iOS开发我为什么弃用Objective-C而选择RubyMotion?

Hendrik Mans是德国汉堡市的一名程序员,他从事iOS开发已有很长一段时间了,起初他一直使用Objective-C语言进行编程而忽视了RubyMotion.从前他认为 RubyMotion只是个介于Ruby和Objective-C之间的交叉编译器,但后来他发现自己完全错了,现在Hendrik已彻底改变了自己的想法. RubyMotion 关于Ruby语言 Hendrik以前不仅从未用过 Ruby,还没少嘲笑过它.而现在Hendrik却认为,Ruby绝对是一种有着清晰漂亮语法的编程语言.R

【iOS开发每日小笔记(一)】UIPickerView 自动选择某个component的某个row

从这篇文章开始我将会把每天在开发过程中遇到的,可以用很短的文章.很小的demo演示解释出来的小心得小技巧,分享在[iOS开发每日小笔记]这个分类中.该分类的文章,内容涉及的知识点可能是很简单的.或是用很短代码片段就能实现的,但在我看来它们会给用户体验.代码效率得到一些提升,记录在这里,90%的作用是帮助自己回顾.记忆.复习.如果看官觉得太easy,可以选择:1,移步[iOS探究]分类,对那里的文章进行斧正:2,在本文的评论里狠狠吐槽,再关掉页面!感谢! 今天在项目中遇到这样一个小问题:我使用UI