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
相关产品推荐
相关产品推荐

