使用 API 请求重构嵌套函数

Swift refactor nested function with API request

提问人:Yuuu 提问时间:9/1/2021 更新时间:9/1/2021 访问量:356

问:

我正在处理 Swift 中的 API 调用,对此有一些疑问。 我以前经历过 JavaScript API 调用,我想在我的 Swift 项目中添加 async/await 的东西。但是由于我使用的是 Swift 5,所以我还不能使用 async / await(我听说我可以从 Swift 5.5 使用它)。

我正在为 API 调用编写一个函数,并在我的项目中重新加载集合视图,如下代码所示。

var events = [Event]()

func populateCV() {
    var snapshot = NSDiffableDataSourceSnapshot<Section, Event>()

    // What I want to do here
    1. fetchEvents() // call "fetchEvents" function and get events with API request and update the events array above.
    2. snapshot.appendItems(events) // append items (events array) to snapshot variable
    3. collectionViewDataSource?.apply(snapshot) // reflect the changes with the new snapshot
    
}


func fetchEvents() {
    // in this function I used Alamofire and I've got the data back (which is "result" below), and I update the events array with results array.
    events = results
}

基本上,我在这里要做的是按 API 请求结果更新事件数组,然后将更新的事件添加到快照中以更新 collectionview。

由于 API 请求需要一些时间,因此我想等待 的调用,直到 API 调用完全更新事件数组。snapshot.appendItems(events)collectionViewDataSource?.apply(snapshot)

因此,我向 fetchEvents 添加了补全功能并编写如下内容。

var events = [Event]()

func populateCV() {
    var snapshot = NSDiffableDataSourceSnapshot<Section, Event>()

    fetchEvents {
        snapshot.appendItems(self.events)
        self.collectionViewDataSource?.apply(snapshot)
    }
    
}


func fetchEvents(completion: @escaping () -> Void) {
    // in this function I used Alamofire and I've got the data back (which is "result" below), and I update the events array with results array.
    events = results
    DispatchQueue.main.async {
        completion()
    }
}

它现在正在工作,但我想知道如果我必须完成几个完成,我的代码会变得混乱。

例如,获取数据并在嵌套函数中使用数据,然后使用从前一个函数获取的数据...等等。 我想在这种情况下,我的函数会变成类似

 fetchEvents {
     doTask1 {
        doTask2 {
            // and more...
        }
     }
 }

因此,如果我想避免那些回调地狱,我该如何在 Swift 中编写补全呢? 此外,我在第二个 fetchEvents 函数中添加了完成功能,但是否有更干净的代码来使用从 API 调用新返回的数据更新集合视图?

iOS Swift API 回调

评论

0赞 jnpdx 9/1/2021
研究 Combine 及其 Future 出版商可能是个好主意。

答:

0赞 CloudBalancing 9/1/2021 #1

是的,这是在 Swift 中使用补全范式的缺点之一。毫无疑问,async/await 使用起来会很棒。 如果您坚持使用完成范式,我不知道有什么方法可以解决它。

你可以改变你的代码,使用Reactiv(使用RxSwift或Combine)范式,同时用Observables包装你的补全。

例如:

fetchEvents(escaping completion: (Result<[Event]>) -> ()) {
... Alamofire and parsing code
}

将使用 RxSwift 重写为

fetchEvents() -> Observalbe<[Event]> {
  return Observable.create { [weak self] observer -> Disposable in
    fetchEvents { events in
      observer.onNext(events)
      observer.onCompleted()
  }
  return Disposables.create()
}

}

因此,对于其他函数和 .doTask1doTask1

当你来链接它们时,它会看起来像这样

fetchEvents()
  .map/flatMap/do { return doTask1 ... (rx operator if you want to map the events}
  .map/flatMap/do { return  doTask2 ... (rx operator if you want to map the events}

另一种选择是像在 Javascript 中一样使用 Promise

看看它是一个很好的框架。https://github.com/mxcl/PromiseKit

如果 PromiseKit 在您的案例中似乎是一个开销,您可以从 John Sundell 的这篇关于如何创建自己的 Promise/Future 并将它们链接起来的精彩文章中汲取灵感