【问题标题】:Swift refactor nested function with API requestSwift 使用 API 请求重构嵌套函数
【发布时间】:2021-10-30 13:09:33
【问题描述】:

我正在处理 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 请求结果更新事件数组,然后将更新的事件添加到快照中以更新集合视图。

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

所以,我将完成添加到 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 调用新返回的数据更新集合视图?

【问题讨论】:

  • 看看 Combine 及其 Future 出版商可能是个好主意。

标签: ios swift api callback


【解决方案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 中一样使用 Promises

看看https://github.com/mxcl/PromiseKit,这是一个很棒的框架。

如果 PromiseKit 在您的情况下看起来像是一种开销,您可以从 John Sundell 撰写的关于如何创建自己的 Promise/Future 并将它们链接起来的精彩文章 this 中获取灵感

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-21
    • 2019-09-19
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 2021-03-03
    • 1970-01-01
    相关资源
    最近更新 更多