用于在管道结果的同时链接异步操作的GCD模式

时间:2016-07-06 08:08:46

标签: swift cocoa cocoa-touch asynchronous grand-central-dispatch

来自JavaScript世界使用async javascript promises,我相信在Swift中使用GCD异步队列也是如此。

您能否指出一个示例,其中队列中指定了2到3个异步函数,其中一个异步操作将结果提供给第二个,第二个将结果提供给第三个(通常称为管道结果)和然后最后是一个结果和错误处理程序。

所有函数都按设计限制为单个参数。

如果在功能2期间发生任何错误,则跳过功能3并将错误直接传递给错误处理程序。

寻找原生解决方案,而不是任何第三方PromiseMonad库。

欣赏swift 3.0代码。

编辑。还从示例中了解到,步骤更像是GCD中的手动线性路径,其中开发人员是下一次的馈送结果并且每次都检查错误,使用Function Compositions可以进行任何功能编程吗?

我想避免Pyramid of Doom并寻找linear async programming

2 个答案:

答案 0 :(得分:2)

我已通过支持请求与Apple联系,他们将我转介到此WWDC15视频Advance NSOperations

我没有看到如何将结果从一个子操作传递到另一个子操作,现在基于此视频,如果有人可以编写一些全面的示例代码,其中一个例程执行后将结果传递给下一个,我&# 39; d接受答案。

答案 1 :(得分:2)

标准库中没有对此的支持,可能不会有一段时间。有很棒的第三方库,但如果你不想要那些,你可以自己定义一个最小值(我在这里使用Swift 3):

enum Result<R> {
    case Success(R)
    case Failure(ErrorProtocol)
}

typealias Async<A, B> = (a: A, handler: (Result<B>) -> Void) -> Void

infix operator • {
    associativity right
    precedence 190
}

func •<A, B, C>(f: Async<A, B>, g: Async<B, C>) -> Async<A, C> {
    return { a, handler in
        f(a: a, handler: { result in
            switch result {
            case .Success(let b): g(a: b, handler: handler)
            case .Failure(let e): handler(.Failure(e))
            }
        })
    }
}

用法示例:

func f(n: Int, h: (Result<String>) -> ()) {
    h(.Success(n.description))
}

func g(s: String, h: (Result<Int>) -> ()) {
    h(.Success(s.characters.count))
}

let chained = f • g

chained(a: 10) { result in
    switch result {
    case .Success(let r): print("Success: \(r)")
    case .Failure(let e): print("Error: \(e)")
    }
}

高级用法示例:

enum Error : ErrorProtocol {
    case NoResult
    case StringDecoding
}

extension URLSession {
    func getData(with url: URL, completionHandler: (Result<(Data, URLResponse)>) -> Void) {
        let task = dataTask(with: url) { (data, response, error) in
            if let error = error {
                completionHandler(.Failure(error))
            } else if let data = data, response = response {
                completionHandler(.Success((data, response)))
            } else {
                completionHandler(.Failure(Error.NoResult))
            }
        }

        task.resume()
    }
}

func decode(d: (Data, URLResponse), handler: (Result<String>) -> Void) {
    DispatchQueue(label: "async").async{
        if let string = String(data: d.0, encoding: .utf8) {
            handler(.Success(string))
        } else {
            handler(.Failure(Error.StringDecoding))
        }
    }
}

let getString = URLSession.shared().getData • decode


getString(a: URL(string: "https://www.reddit.com")!) { result in
    switch result {
    case .Success(let string): print(string)
    case .Failure(let e): print(e)
    }
}