swift - 如何处理完成关闭中的多个错误

标签 swift closures

我正在实现一个函数,它接受一个数组和一个完成闭包。我遍历数组中的项目,根据每个项目执行网络请求。当每个请求完成时,它将其结果附加到一个集合中。

一旦所有请求都返回,函数的完成 block 将调用累积的集合。

我的问题是我不确定如何处理网络请求可能提供的(可能是多个)错误。有没有一种标准的方法来处理这种模式?想到的第一个想法是:

  • 一旦给出网络请求错误,就调用函数的完成闭包,返回 nil 结果和该错误。

  • 在所有网络请求都完成后,使用某种结构调用完成闭包,其中包含成功完成的调用的结果和未成功完成的调用的错误。

    <

这些选项似乎都不理想。有没有标准的方法来处理这个问题?我不确定此功能的用户会合理期望什么。

我正在 Swift 3.1 中实现它。

最佳答案

我不知道你的完成闭包看起来如何,但你可以考虑使用一个 enum 和一个关联的结果值(here you can read more about associated values)。

如果您像这样创建一个枚举:

enum ClosureResult {
   case success([String])
   case failure([String], [Error])
}

您可以根据网络查找是失败还是成功返回不同的值。请注意,在我的 failure 案例中,我传递了一组 Error 对象作为第二个参数,我不知道这是否适合你,但这只是为了说明您可以传递多个参数作为返回。

如果您随后使用 ClosureResult 作为完成闭包的返回值,您可以在返回并依赖于值(value)。

因此,您的函数可能如下所示:

func yourFunction(items: [String], completion: (ClosureResult) -> Void) {
    var completedItems = [String]()
    var failedItems = [Error]()
    for item in items {
        //Do your network magic here 
        //if it succeeds add it to completedItems
        //if it fails, add it to failedItems
    }

    //did we encounter any failures?
    if failedItems.count > 0 {
        //yes we did, return a .failure then
        let failure = ClosureResult.failure(completedItems, failedItems)
        completion(failure)
    } else {
        //no...return .success
        let success = ClosureResult.success(completedItems)
        completion(success)
    }
}

然后你可以像这样使用它:

let items = ["a", "b", "c"]
yourFunction(items: items) { result in
    switch result {
    case .success(let okItems):
        print(okItems)
    case .failure(let okItems, let failedItems):
        print(failedItems)
    }
} 

更新

在你的评论中你问:

My only concern is that in, in your example, the network request succeeds on "a" and "c" but not "b", the closure result contain any information about which item failed. Would it be reasonable to return tuples of the items and the network result for that item in the ClosureResult object instead of just strings?

是的,这是有道理的。我只是使用 StringError 作为示例,但您也可以使用自己的类。

我想,我会做的是,我会创建一个简单的类并返回它,而不是使用元组。

例如:

struct ClosureError {
    let item: String
    let error: Error
}

然后你的 ClosureResult 枚举可以使用它:

enum ClosureResult {
   case success([String])
   case failure([String], [ClosureError])
}

在您的 yourFunction 中,您需要在遇到故障时创建一个新的 ClosureError 实例:

    ...
    var failedItems = [ClosureError]()
    ...
    for item in items {
        //Do your network magic here 
        //if it succeeds add it to completedItems
        //if it fails, add it to failedItems
        let error = //create the error
        let closureFailure = ClosureFailure(item, error)
        failedItems.append(closureFailure) 
    }
    ...

最后,在您的 switch 中,您会知道哪些项目失败了:

let items = ["a", "b", "c"]
yourFunction(items: items) { result in
    switch result {
    case .success(let okItems):
        print(okItems)
    case .failure(let okItems, let failedItems):
        for closureError in failedItems {
            print("item: \(closureError.item) has failed with error \(closureError.error)"
        }
    }
} 

你应该为各个部分想出一些更好的名字 :)

希望有意义并且可以使用。

关于swift - 如何处理完成关闭中的多个错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44132704/

相关文章:

closures - 为什么 [weak self] 有效但 [unowned self] 在 Swift 闭包中中断?

function - Scala中有lambda函数吗?

JavaScript:闭包帮助

ios - 从 URL 方案打开完全退出的应用程序未从 iOS 中的 postNotificationName 调用该函数

ios - 按不区分大小写的属性对 Realm 结果进行排序

ios - 在 CoreBluetooth 中使用两个特性不起作用

javascript - 在闭包上下文中 for 循环内声明的 let 变量的行为

ios - UIViewController 使用闭包时不释放

swift - 无法连接到 AWS EC2 上的 Realm 服务器

ios - SwiftUI View 入门代码在添加到现有项目时提示 `inheritance from non-protocol type ' View'`