Swift 5.5: Как объединить одновременные результаты API от нескольких закрытий в единую структуру перед обновлением TableView?

#ios #swift #api #rest #concurrency

#iOS #быстрый #API #остальное #совпадение

Вопрос:

Я пытаюсь объединить три результата API JSON от трех одновременных вызовов в единую структуру данных (например, CombinedDataStructure), которая будет передана в мой TableView по протоколу делегирования. Я знаю, как отправлять результаты из этих API независимо друг от друга, каждый через свою собственную функцию протокола, но я хотел бы обновлять представление таблицы только тогда, когда все полученные данные доступны не по одному. Я застрял на объединении результатов закрытия API в структуру данных. Независимо от того, что я пытаюсь, я не могу извлечь и объединить значения из замыканий в один тип данных

API1 (два других аналогичны):

 func getPrice (completion: @escaping (String) -gt; ()) {   let urlString = "https://myApi.com/api/ticker/price?symbol=xxxx"  var testReturnString = "No value" //   //Make API call  if let url = URL(string: urlString){  let session = URLSession(configuration: .default)  let task = session.dataTask(with: url) { data, response, error in  if error != nil {  print(error as Any)  }  if let safeData = data {  let decoder = JSONDecoder()  do {  let decodedData = try decoder.decode(PriceData.self, from: safeData)   testReturnString = decodedData.price  print("Inside getPrice Closure:(testReturnString)") //-gt; Here we see correct data from server    //testStructStr = decodedData.price -gt; Struct variable assignment - Forces the API to becomes mutating and throws "Cannot use mutating member on immutable value: 'self' is immutable"    completion(testReturnString)    } catch {  print(error)  }  }  }  task.resume()  print("Outside Closure:(testReturnString)") //-gt; Here we see "No Value"  }  }  

Часть параллелизма выполняется в updateBalanceTable, которая вызывается в viewDidLoad :

 func updateBalanceTable(){  let radQueue = OperationQueue()  var testStrUpdate = "No Value 2"    let operation1 = BlockOperation {  let group = DispatchGroup()    //API1  group.enter()  getCoinPrice { myStr in  print("Inside updateBalanceTable closure:(myStr)")  testStrUpdate = myStr  }  group.leave()    //API2  group.enter()  //getExchangeInfo() - not expanded with closures yet  group.leave()    //API3  group.enter()   //getAllBalances() - not expanded with closures yet  group.leave()    group.wait()  //this operation won't return until we have all data  print("Test StrUpdate inside Wait OP1:(testStrUpdate)")    }  let operation2 = BlockOperation {  print("Test StrUpdate inside OP2:(testStrUpdate)")  // Now, operation2 will fire off once operation1 has completed, with results wanted  }  operation2.addDependency(operation1)  radQueue.addOperation(operation1)  radQueue.addOperation(operation2)  }  

All these functions are defined inside a struct called BalanceManager:

 struct BalanceManager{    var delegate: BalanceProtocol?  var testStructStr = "" //I have tried updating a string from Struct directly but I get other errors doing so   func getPrice (completion: @escaping (String) -gt; ()) { ... }  func getExchangeInfo(completion: @escaping ([Pairs]) -gt; ()) { ... }  func getAllBalances(completion: @escaping ([Assets]) -gt; ()) { ... }  func updateBalanceTable() { ... } }  

Результаты консоли:

 Outside Closure: No value Test StrUpdate inside Wait OP1: No Value 2 Test StrUpdate inside OP2: No Value 2 Inside getPrice Closure: 1234.45 Inside updateBalanceTable closure: 1234.45