xcode 如何在元组中保存响应时忽略异步let抛出的错误?

t8e9dugd  于 2023-02-09  发布在  其他
关注(0)|答案(2)|浏览(125)

我有这样一个准则:

Task {
    async let configsReq = self.interactor.getConfigs()
    async let optionsReq = self.interactor.getOptions()
    async let updateStateReq = self.interactor.getAppUpdateState()
    async let contactsReq = self.interactor.getContactOptions()

    var config: Config?
    var options: AvailableOptions?
    var updateState: UpdateType?
    var contacts: ContactOptions?

    do {
        config = try await configsReq
    } catch {
        config = nil
    }

    do {
        options = try await optionsReq
    } catch {
        options = nil
    }

    do {
        updateState = try await updateStateReq
    } catch {
        updateState = nil
    }

    do {
        contacts = try await contactsReq
    } catch {
        contacts = nil
    }

    self.goToNextPage()
}

在这种情况下,请求得到正确的响应或抛出错误对我来说并不重要。我不想阻止用户得到正确的响应。而且我还想确保我所有的请求都得到了响应(正确或错误响应),以便将用户带到下一页
我怎样才能用新的swift并发更好更干净地写这些代码?我试过了(但是我不能得到每个相关请求的匹配错误):

Task {
    async let configs = self.interactor.getConfigs()
    async let options = self.interactor.getOptions()
    async let updateState = self.interactor.getAppUpdateState()
    async let contacts = self.interactor.getContactOptions()

    do {
        let array = try await [configs, options, updateState, contacts]
    } catch {
        print(error)
    }
}
lnlaulya

lnlaulya1#

我将创建一个小助手,帮助将错误封装到Result中:

extension Result {
    init(asyncCatching block: () async throws -> Success) async where Failure == Error {
        do {
            self = .success(try await block())
        } catch {
            self = .failure(error)
        }
    }
}

如果出现错误,您甚至可以为每个getXXX方法获得Error对象,而不仅仅是nil。当然,如果您真的只需要nil,您可以编写一个helper来返回可选项。

// this is essentially like refactoring out the repeated parts of your first code
func asyncCatchWithNil<Result>(function: () async throws -> Result) async -> Result? {
    do {
        return try await function()
    } catch {
        return nil
    }
}

然后你可以这样做:

Task {
    async let configs = Result(asyncCatching: self.interactor.getConfigs)
    async let options = Result(asyncCatching: self.interactor.getOptions)
    async let updateState = Result(asyncCatching: self.interactor.getAppUpdateState)
    async let contacts = Result(asyncCatching: self.interactor.getContactOptions)
    /* or
    async let configs = asyncCatchWithNil(function: self.interactor.getConfigs)
    async let options = asyncCatchWithNil(function: self.interactor.getOptions)
    async let updateState = asyncCatchWithNil(function: self.interactor.getAppUpdateState)
    async let contacts = asyncCatchWithNil(function: self.interactor.getContactOptions)
    */

    let (configsResult, optionsResult, updateStateResult, contactsResult) 
        = await (configs, options, updateState, contacts)

    // you can inspect each result here if you'd like
    
    self.goToNextPage()
}

这里的想法是,您在async let点获得一个可以同时包含response * 和 * 错误的类型,而不是在以后捕获错误。

v09wglhw

v09wglhw2#

如果我理解正确的话,您需要:

  • "将错误匹配到每个相关请求",但
  • 不管成功或失败,您都希望继续,因为"请求得到正确响应或引发错误对我来说无关紧要"。

如果这就是您要寻找的模式,我建议使用Taskresult

async let configsReq  = Task { try await interactor.getConfigs() }
async let optionsReq  = Task { try await interactor.getOptions() }
async let stateReq    = Task { try await interactor.getAppUpdateState() }
async let contactsReq = Task { try await interactor.getContactOptions() }

let config   = await configsReq.result
let options  = await optionsReq.result
let state    = await stateReq.result
let contacts = await contactsReq.result

goToNextPage(config: config, options: options, state: state, contacts: contacts)

或者,更简洁地说:

async let configs  = Task { try await interactor.getConfigs() }
async let options  = Task { try await interactor.getOptions() }
async let state    = Task { try await interactor.getAppUpdateState() }
async let contacts = Task { try await interactor.getContactOptions() }

await goToNextPage(config: configs.result, options: options.result, state: state.result, contacts: contacts.result)

其中goToNextPage可定义为:

func goToNextPage(
    config:   Result<Config, Error>,
    options:  Result<AvailableOptions, Error>,
    state:    Result<UpdateType, Error>,
    contacts: Result<ContactOptions, Error>
) { … }

这样,goToNextPage可以查看每个请求的.success.failure,以检索与四个请求中的每个请求关联的值或错误。
不用说,你也可以为这四个请求设置四个属性,然后goToNextPage可以引用这些属性,而不是把它们作为方法的参数。这在功能上是一样的,但是你必须决定是把本地变量传递给下一个方法,还是更新下一个方法访问的属性。
你问:
......如果我们不想再使用Result,怎么办?
是的,我们不再经常使用Result,因为在传统的异步模式中,它在历史上是一种返回值或错误的模式,而现在我们使用try执行一系列任务,捕捉抛出的错误,但通常在其中一个失败时提前退出。
但是,如果您真的希望捕获四个并发请求中每个请求的成功和失败,那么Result可以很好地封装它们。

相关问题