Swift中如何异步请求两个URL并解析返回的JSON数据
实现方案
你可以通过DispatchGroup来管控多个异步请求的执行状态,等两个URL的拉取解析都完成后再统一刷新UI,同时复用现有解析逻辑即可,具体修改步骤如下:
- 第一步:把单URL拉取解析的逻辑从viewDidLoad中抽成独立复用方法,避免重复写代码
- 第二步:使用DispatchGroup对两个请求做计数,每个请求开始前调用
enter(),请求完成(无论成功失败)都调用leave() - 第三步:通过DispatchGroup的
notify方法监听所有请求完成的时机,统一触发UI刷新 - 补充:为了避免两个异步回调同时操作customers数组导致的数据异常,新增一个串行队列专门处理customers数组的读写操作,保证线程安全
import UIKit class ViewController: UIViewController { @IBOutlet weak var customerNameLabel: UILabel! @IBOutlet weak var cardNumberLabel: UILabel! @IBOutlet weak var dateNTimeLabel: UILabel! @IBOutlet weak var amountLabel: UILabel! var customers = [Customer]() var currentCustomerIndex = 0 // 串行队列,保证customers数组操作线程安全 private let dataQueue = DispatchQueue(label: "com.yourname.customerDataQueue") // 网络请求通用session,避免重复创建 private let session = URLSession(configuration: .default) override func viewDidLoad() { super.viewDidLoad() let group = DispatchGroup() // 替换为你的两个JSON接口地址 guard let url1 = URL(string: "第一个URL地址"), let url2 = URL(string: "第二个URL地址") else { print("URL格式非法") return } // 发起第一个请求 group.enter() fetchAndParseData(url: url1, group: group) // 发起第二个请求 group.enter() fetchAndParseData(url: url2, group: group) // 所有请求完成后刷新UI group.notify(queue: .main) { [weak self] in self?.displayData() } } // 抽离的单URL拉取+解析通用方法 private func fetchAndParseData(url: URL, group: DispatchGroup) { let task = session.dataTask(with: url) { [weak self] data, response, error in // 无论请求成功失败都要离开group,避免死等 defer { group.leave() } if let error = error { print("数据请求失败,错误信息:" + error.localizedDescription) return } guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200, let validData = data else { print("JSON数据生成失败") return } do { let jsonObj = try JSONSerialization.jsonObject(with: validData, options: .mutableContainers) as? [Any] // 切换到串行队列解析数据,避免多线程同时操作customers数组 self?.dataQueue.async { self?.ParseData(jsonObject: jsonObj) } } catch { print(error.localizedDescription) } } task.resume() } func ParseData(jsonObject: [Any]?) { guard let json = jsonObject else { print("解析失败,可选值解包失败") return } for firstLevelItems in json { guard let object = firstLevelItems as? [String: Any], let fname = object["first_name"] as? String, let lname = object["last_name"] as? String, let fullName = fname + " " + lname as? String, let customerNumber = object["customer_number"] as? Int, let purchase = object["purchase"] as? [String: Any], let time = purchase["time"] as? String, let date = purchase["date"] as? String, let amount = purchase["amount"] as? String else { continue } // 嵌套函数:添加交易记录 func addTransaction(_customer: Customer) { if let cardNumber = purchase["card_number"] as? String? { _customer.transactions.append(Transaction(firstName: fname, lastName: lname, time: time, date: date, amount: amount, cardNumber: cardNumber)) } else { _customer.transactions.append(Transaction(firstName: fname, lastName: lname, time: time, date: date, amount: amount)) } } let filteredCustomers = customers.filter({ (customer) -> Bool in return customer.transactions[currentCustomerIndex].customerName == fullName }) if filteredCustomers.count == 0 { customers.append(Customer(customerNumber: customerNumber)) addTransaction(_customer: customers.last!) } else if filteredCustomers.count == 1 { addTransaction(_customer: filteredCustomers[0]) } else { assertionFailure("客户数组中不允许存在重复客户") } } } func displayData() { // 操作customers数组前先切到串行队列读数据,再切回主队列刷新UI dataQueue.async { [weak self] in guard let self = self, self.currentCustomerIndex < self.customers.count else { return } let customer = self.customers[self.currentCustomerIndex] DispatchQueue.main.async { self.customerNameLabel.text = customer.customerName self.cardNumberLabel.text = customer.cardNum self.dateNTimeLabel.text = customer.dateNTime self.amountLabel.text = "$" + customer.customerAmount.description } } } @IBAction func changeCustomer(_ sender: UIButton) { dataQueue.async { [weak self] in guard let self = self else { return } self.currentCustomerIndex += sender.tag if self.currentCustomerIndex < 0 { self.currentCustomerIndex = self.customers.count - 1 } else if self.currentCustomerIndex >= self.customers.count { self.currentCustomerIndex = 0 } DispatchQueue.main.async { self.displayData() } } } }
内容的提问来源于stack exchange,提问作者Molag_Bork
相关产品推荐
相关产品推荐

