You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 4 - URLSession解析ADX网站API遇技术问题求助

解决Swift 4中用URLSession解析ADX API的问题

嘿,我来帮你搞定这个ADX API解析的事儿!刚好我之前处理过类似的金融类API,给你梳理下具体的实现步骤和要注意的坑,完全贴合Swift 4的环境:

第一步:定义对应JSON结构的Codable模型

Swift 4引入的Codable协议是解析JSON的利器,我们先根据两个API的返回结构定义模型(注意要和API返回的字段严格对应,大小写敏感哦):

公司列表模型

struct ListedCompany: Codable {
    let companyID: String
    let companyName: String
    
    // 映射API返回的字段名,比如API里的key是"ListedCompanyID"和"CompanyName"
    enum CodingKeys: String, CodingKey {
        case companyID = "ListedCompanyID"
        case companyName = "CompanyName"
    }
}

公司详情模型

struct CompanyOrderBook: Codable {
    let lastTradedPrice: Double
    
    enum CodingKeys: String, CodingKey {
        case lastTradedPrice = "LastTradedPrice"
    }
}

第二步:封装通用网络请求函数

避免重复写URLSession的模板代码,封装一个通用的fetch函数,支持任意Codable类型:

func fetchCodableData<T: Codable>(from urlString: String, completion: @escaping (Result<T, Error>) -> Void) {
    guard let url = URL(string: urlString) else {
        completion(.failure(NSError(domain: "ADXAPI", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效的API地址"])))
        return
    }
    
    let task = URLSession.shared.dataTask(with: url) { data, response, error in
        // 处理网络错误
        if let error = error {
            completion(.failure(error))
            return
        }
        
        // 检查HTTP响应状态码
        guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
            completion(.failure(NSError(domain: "ADXAPI", code: -2, userInfo: [NSLocalizedDescriptionKey: "API返回错误状态码"])))
            return
        }
        
        // 解析JSON数据
        guard let data = data else {
            completion(.failure(NSError(domain: "ADXAPI", code: -3, userInfo: [NSLocalizedDescriptionKey: "未获取到数据"])))
            return
        }
        
        do {
            let decoder = JSONDecoder()
            // 如果API返回日期格式特殊,可以在这里设置dateDecodingStrategy
            let decodedData = try decoder.decode(T.self, from: data)
            completion(.success(decodedData))
        } catch let decodingError {
            completion(.failure(decodingError))
        }
    }
    
    task.resume()
}

第三步:实现两个API的具体请求

获取公开公司列表

func fetchPublicListedCompanies(completion: @escaping (Result<[ListedCompany], Error>) -> Void) {
    let apiUrl = "https://www.adx.ae/en/_vti_bin/adx/svc/Members.svc/ListedCompanies?showPrivate=false&showPublic=true"
    fetchCodableData(from: apiUrl, completion: completion)
}

根据ID获取公司交易详情

func fetchCompanyDetails(with companyID: String, completion: @escaping (Result<CompanyOrderBook, Error>) -> Void) {
    let apiUrl = "https://www.adx.ae/en/_vti_bin/ADX/svc/trading.svc/ListedCompanyOrderBook?listedCompanyID=\(companyID)"
    fetchCodableData(from: apiUrl, completion: completion)
}

第四步:整合逻辑,列出公司名称和对应价格

现在可以把两个API的请求结合起来,获取所有公开公司的名称和最新交易价格:

func loadAndDisplayCompanyData() {
    fetchPublicListedCompanies { result in
        switch result {
        case .success(let companies):
            // 控制并发请求数,避免一次性发起太多请求被限制
            let operationQueue = OperationQueue()
            operationQueue.maxConcurrentOperationCount = 5
            
            for company in companies {
                let operation = BlockOperation {
                    self.fetchCompanyDetails(with: company.companyID) { detailsResult in
                        DispatchQueue.main.async {
                            switch detailsResult {
                            case .success(let details):
                                print("\(company.companyName) 最新成交价: \(details.lastTradedPrice) AED")
                                // 这里更新你的UI,比如TableView的数据源
                            case .failure(let error):
                                print("获取\(company.companyName)详情失败: \(error.localizedDescription)")
                            }
                        }
                    }
                }
                operationQueue.addOperation(operation)
            }
            
        case .failure(let error):
            print("获取公司列表失败: \(error.localizedDescription)")
        }
    }
}

关键注意事项

  • UI更新必须回到主队列:网络请求在后台线程执行,所有UI操作一定要用DispatchQueue.main.async包裹
  • 字段映射要准确:ADX的API字段是PascalCase格式,一定要在CodingKeys里准确映射,大小写错了会解析失败
  • 控制并发数:如果公司数量较多,一次性发起几十上百个请求可能会被服务器限流,用OperationQueue限制并发数更稳妥
  • 错误处理要全面:覆盖网络错误、无效URL、非2xx状态码、解析失败等场景,方便排查问题

内容的提问来源于stack exchange,提问作者Abdulla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:28:52