PromiseKit,来自 Promise 这个的概念,它可以帮助我们的代码变得更加简洁优雅。 我们今天就来聊聊它。
Promise 这个概念之前更多应用于 JavaScript, 主要是为了解决 JavaScript 的 Callback Hell(回调地狱) 问题。 简单来说就是, JS 中很异步函数都是用 callback 的形式返回结果,而开发者经常会连续的使用这些异步调用,最后就导致回调嵌套的层级越来越深,严重影响代码的结构和可读性。
关于 Callback Hell, 还有一个外国朋友专门建立了一个页面 - http://callbackhell.com , 大家有兴趣的话可以了解一下。
Promise 的出现,就是用来解决 Callback Hell 这个问题的。它用线性调用的接口来封装回调嵌套这些问题, 在 JavaScript 中的应用比较广泛。 JS 有一个专门的第三方库就叫做 Promises:
https://www.promisejs.org
介绍完了背景, 我们就来继续来了解 PromiseKit 吧。 PromiseKit 是专门针对 Swift 和 Objective-C 语言的解决方案。 我们先看看他能用来干什么。
如果用 iOS 原生的接口,我们要弹出一个 UIAlertView 对话框,并处理点击事件的话, 大概需要这样做:
func showAlert() {
let alert = UIAlertView(title: "Title", message: "Msg", delegate: self, cancelButtonTitle: "Cancel", otherButtonTitles: "OK")
alert.show()
}
func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {
print("button index /(buttonIndex)")
}
我们先要创建一个 UIAlertView, 然后还要指定它的代理, 如果我们需要一些中间变量的话, 还需要将这些变量声明为类的属性, 以便这两个方法都能从全局来访问。 我们开发 iOS App 的时候,这种情况非常多。
那么咱们再来看看用 PromiseKit 来处理这个问题的方法:
import PromiseKit
func testAlert() {
let alert = UIAlertView(title: "Title", message: "Msg", delegate: nil, cancelButtonTitle: "Cancel", otherButtonTitles: "OK")
alert.promise().then { buttonIndex in
print("ok /(buttonIndex)")
}
}
这次我们没有用任何的代理方法, 而是直接用 PromiseKit 对 UIAlertView 提供的扩展, 在一个方法中将 UIAlertView 的创建和事件处理声明完成。
PromiseKit 对很对 iOS 提供的控件都提供了类似的扩展, 比如 UIActionSheet
, NSURLConnection
, UIViewController
, CLLocationManager
等等。
链式调用是 PromiseKit 的核心特性,比如这样的代码:
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: "http://aaa.cc")!) { data, response, error in
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: "http://bbb.cc")!) { data, response, error in
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: "http://ddd.cc")!) { data, response, error in
print("finished")
}
}
}
这个就是 Callback Hell, dataTaskWithURL 方法的回调闭包一级一级的嵌套。 现在我们这个示例中每个闭包没有太多代码量, 但在实际的项目中,往往这些嵌套的闭包中都含有大量的代码,这样就会严重影响我们阅读这些代码。
再来看看 PromiseKit 的处理方式:
NSURLSession.sharedSession().promise(NSURLRequest(URL: NSURL(string: "http://aaa.cc")!)).then { data in
return NSURLSession.sharedSession().promise(NSURLRequest(URL: NSURL(string: "http://bbb.cc")!))
}.then { data in
return NSURLSession.sharedSession().promise(NSURLRequest(URL: NSURL(string: "http://ddd.cc")!))
}.then { data in
print("finished")
}
这个就是 Promise 的处理方式了, 它的每一层闭包中,我们可以再返回一个 Promise 对象,然后本来是层级嵌套的逻辑, 就变成了线性的逻辑了。 当代码量变大的时候, 我们依然能够很方便的分清楚代码的逻辑结构。
有些时候,我们可能会依赖于某些异步任务,需要等他们执行完成后,再进行一些操作。 PromiseKit 为我们提供了这样方便的接口, 比如这样:
let req1 = NSURLSession.sharedSession().promise(NSURLRequest(URL: NSURL(string: "http://bbb.cc")!))
let req2 = NSURLSession.sharedSession().promise(NSURLRequest(URL: NSURL(string: "http://ddd.cc")!))
when(req1, req2).then { resp1, resp2 in
}.error { err in
}
PromiseKit 的 when 函数, 会等到 req1 和 req2 两个请求执行完毕后,在执行后面的闭包,如果期间发生错误, error 就会被调用。
以上就是 PromiseKit 的基本介绍了, 关于它的更多内容,可以参看 Github 主页:
https://github.com/mxcl/PromiseKit
如果你之前有过其他平台 Promise 的使用经验, 相信上手应该不难。 它确实可以让你的代码简单很多,当然至于是否要采用这种风格,也是见仁见智了。这里抛砖引玉,给大家多提供一种选择。