有一种 Block 叫 Callback,有一种 Callback 叫 CompletionHandler

【引言】iOS10推送部分的API,大量使用了 CompletionHandler 这种命名方式,那么本文我们将对比下这种 Block 的特殊性,以便更好的理解和在自己的项目中实践 CompletionHandler 样式的 Blcok。

正文

我们作为开发者去集成一个 Lib (也可以叫轮子、SDK、下文统一叫 Lib)时,我们会发现我们遇到的 Block, 按照功能的角度划分,其实可以分为这几种:

  • Lib 通知开发者,Lib操作已经完成。一般命名为 Callback
  • 开发者通知 Lib,开发者的操作已经完成。一般可以命名为 CompletionHandler。

这两处的区别: 前者是 “Block 的执行”,后者是 “Block 的填充”。

Callback vs CompletionHandler 命名与功能的差别,Apple 也没有明确的编码规范指出过,只不过如果按照“执行与填充”的功能划分的话,callbackcompletionHandler 的命名可以区分开来对待。同时也方便调用者理解 block 的功能。但总体来说,Apple 官方的命名中,“Block 填充“这个功能一般都会命名为 “completionHandler”,“Block 执行”这个功能大多命名为了“callback” ,也有少部分命名为了 “completionHandler”。

比如:

NSURLSession 中,下面的函数将 “callback” 命名为了 “completionHandler”:

我们常常见到 CompletionHandler 被用到了第一种场景,而第一种场景“Block 执行”命名为 Callback 则更合适。

不是所有 Block 都适合叫做 CompletionHandler

一般情况下,CompletionHandler 的设计往往考虑到多线程操作,于是,你就完全可以异步操作,然后在线程结束时执行该 CompletionHandler,下文的例子中会讲述下 CompletionHandler 方式在多线程场景下的一些优势。

CompletionHandler + Delegate 组合

在 iOS10 中新增加的 UserNotificaitons 中大量使用了这种 Block,比如:

文档 对 completionHandler 的注释是这样的:

同样在这里也有应用:

还有另外一个也非常普遍的例子(Delegate 方式使用URLSession 时候必不可少的 4个代理函数之一 )

在代理方法实现代码里面,若是不执行 completionHandler(NSURLSessionResponseAllow) 话,http请求就终止了。

CompletionHandler + Block 组合

函数中将函数作为参数或者返回值,就叫做高阶函数。

按照这种定义,Block 中将 Block 作为参数,这也就是高阶函数。

结合实际的应用场景来看一个例子:

如果有这样一个需求:

拿我之前的一个 IM 项目 ChatKit-OC (开源的,下面简称 ChatKit)为例,当你的应用想要集成一个 IM 服务时,可能这时候,你的 APP 已经上架了,已经有自己的注册、登录等流程了。用 ChatKit 进行聊天很简单,只需要给 ChatKit 一个 id 就够了。聊天是正常了,但是双方只能看到一个id,这样体验很不好。但是如何展示头像、昵称呢?于是就设计了这样一个接口,-setFetchProfilesBlock:

这是上层(APP)提供用户信息的 Block,由于 ChatKit 并不关心业务逻辑信息,比如用户昵称,用户头像等。用户可以通过 ChatKit 单例向 ChatKit 注入一个用户信息内容提供 Block,通过这个用户信息提供 Block,ChatKit 才能够正确的进行业务逻辑数据的绘制。

示意图如下:

11224803-31a78b716832c471

具体实现如下:

方法定义如下:

用法如下所示:

对于以上 Fetch 方法的这种应用场景,其实用方法的返回值也可以实现,但是与 CompletionHandler 相比,无法自由切换线程是个弊端。

 

1 3 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部