Forbind 1.0

Forbind 1.0

测试已测试
Lang语言 SwiftSwift
许可证 MIT
发布最新版本2015 年 4 月
SPM支持 SPM

Ulrik Damm 维护。



  • Ulrik Damm

Forbind

Swift 的功能链和承诺

注意:目前仍处于实验状态。一切都有可能改变。我非常希望得到一些反馈。请通过 @ulrikdamm 在推特上给我写邮件。

它是什么

Forbind 是一个库,它将表达式功能链引入到您的 Swift 代码中。它包含很多强大的组件,用于编写无状态和表达式的代码。它的主要特性包括

• 一个用于将表达式连接在一起并处理错误的绑定操作符 (=>)

• 一个用于合并两个潜在的可选值的合并操作符 (++)

• 用于更好地处理错误的 Result 类型

• 用于更好地处理异步值的 Promise 类型

• 一些 Foundation 和 UIKit 的扩展,它将这些 Forbind 概念引入了常用类中。

当您将这些特性组合起来,您就可以开始以全新方式编写代码。无需 if-lets,无需散布在代码中的错误处理,无需多层缩进的代码。

想法是您可以编写一串表达式,这些表达式最终产生一个结果。所有错误处理都留到最后一刻,即在展开结果时进行。对于异步操作也同样有效。不再需要 if-lets,不再需要 NSErrorPointer 检查,不再需要完成区块。您的代码将变成这样

if let data = readFile("file") {
    if let result = parseJson(data, error: nil) as? NSDictionary {
        if let thingy = parseData(result) {
            handleResult(thingy)
        }
    }
}

到这样

readFile("file") => parseJson => parseData => handleResult

展示一个例子

让我们尝试用 NSURLConnection 编做一个简单的网络请求。以下是它今天可能看起来像

class NetworkRequestExampleOldWay {
    func handleResponse(response : NSURLResponse?, data : NSData?) -> String? {
        if let data = data {
            return NSString(data: data, encoding: NSUTF8StringEncoding) as? String
        } else {
            return nil
        }
    }

    func performRequest(completion : (String?, NSError?) -> Void) {
        if let url = NSURL(string: "http://ufd.dk") {
            let request = NSURLRequest(URL: url)
            NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) { response, data, error in
                if let error = error {
                    completion(nil, error)
                } else {
                    if let result = self.handleResponse(response, data: data) {
                        completion(result, nil)
                    } else {
                        completion(nil, nil)
                    }
                }
            }
        }
    }
}

这里有几个问题

• 所有的代码都需要嵌套在 if-let 中。

• 错误和数据可以在同一时间具有值。

• 您可能会忘记处理错误。

• 错误处理和逻辑混合在一起。

• 在多个不同位置进行错误处理。

• 多级缩进。

• 完成调用带有两个 nil?让我们希望这不会造成问题。

• 25 行。

下面是如何使用 Forbind 正确完成相同的任务

class NetworkRequestExampleWithForbind {
    func handleResponse(response : NSURLResponse?, data : NSData?) -> String? {
        return data => { NSString(data: $0, encoding: NSUTF8StringEncoding) as? String }
    }

    func performRequest() -> ResultPromise<String> {
        let request = NSURL(string: "http://ufd.dk") => { NSURLRequest(URL: $0) }
        let response = request ++ NSOperationQueue.mainQueue() => NSURLConnection.sendAsynchronousRequest
        return response => handleResponse
    }
}

这个问题通过这种方式解决

• 在进行任何错误处理之前,您定义了所有逻辑。

• 您被迫处理所有错误。

• 仅在接收最终结果时才进行缩进。

• 只有 9 行!!

有些约定与常规的代码编写方式有所不同

• 嵌套调用变成了链式调用(func1 => func2 而不是 func2(func1())

• 带有多个参数的链式调用用 ++ 连结起来(arg1 ++ arg2 => func 而不是 func(arg1, arg2)

• 最后进行错误处理。如果出现任何问题,则跳过其余部分。

我很好奇。我该如何了解更多信息?

为了获得更多示例,请打开 Xcode 项目并运行 ForbindDemo iOS 应用。它包含一些实际示例。或者,您可以直接查看 动画演示网络请求演示打印 IP 演示 的源代码文件。

整个库都在以下文件中: bind.swiftcombine.swiftdataStructures.swift。每个文件都有注释,详细说明了其工作原理。

如果您想了解更多关于绑定操作符背后的概念,您可以阅读我关于它的 博客文章

项目的状态如何?

它仍然非常实验性,所以我非常希望得到关于它的反馈。我现在不推荐将其用于产品代码。如果您有好的想法或只是有问题,请在 @ulrikdamm 上提交拉取请求或联系我。

仍需考虑的事项

• 项目的总体方向(是否存在一些根本性的缺陷?)

• 暂定取消(支持在暂定被释放时取消异步操作)

• 处理队列(目前暂定回调在操作完成的队列上运行)

• 为常见的 UIKit/AppKit/Foundation 方法添加更多扩展,以使用 Promise 和 Result 而不是 NSErrorPointer 和完成块。

• 对于大表达式,“表达式过于复杂,难以在合理时间内解决”