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

SwiftUI获取含双数组的JSON API并在TabBar展示失败排查

SwiftUI中API数据解析失败:格式错误问题解决

核心问题分析

  • 请求方式错误:错误拼接了API路径,且未按照要求用x-www-form-urlencoded格式传递参数,导致返回的JSON结构与模型不匹配。
  • 模型解码问题:event_chargable_or_not字段返回字符串(如"0")或null,直接映射到Bool类型会解码失败;日期解析未指定locale,易因地区差异导致解析出错。

修正步骤

1. 修复API请求逻辑

直接使用提供的API地址,通过POST请求传递event_type参数,符合接口要求的x-www-form-urlencoded格式:

class ApiService {
    static let baseUrl = "https://dev.myhss.org.uk/api/v1/events/eventlist"
    static let dateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        formatter.locale = Locale(identifier: "en_US_POSIX") // 避免地区差异导致解析失败
        return formatter
    }()
    
    static func fetchEvents(type: EventType, completion: @escaping (Result<EventListing, Error>) -> Void) {
        guard let url = URL(string: baseUrl) else {
            completion(.failure(ApiError.invalidUrl))
            return
        }
        
        // 构建请求参数
        let eventTypeValue = type == .upcoming ? "1" : "2"
        let parameters = "event_type=\(eventTypeValue)"
        let requestBody = parameters.data(using: .utf8)
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.httpBody = requestBody
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            if let error = error {
                completion(.failure(error))
                return
            }
            guard let data = data else {
                completion(.failure(ApiError.noData))
                return
            }
            
            // 打印原始数据方便调试
            if let rawJson = String(data: data, encoding: .utf8) {
                print("返回JSON: \(rawJson)")
            }
            
            do {
                let decoder = JSONDecoder()
                decoder.dateDecodingStrategy = .formatted(dateFormatter)
                let eventListing = try decoder.decode(EventListing.self, from: data)
                completion(.success(eventListing))
            } catch let error {
                print("解码错误详情: \(error)") // 打印详细错误便于排查
                completion(.failure(error))
            }
        }.resume()
    }
    
    enum ApiError: Error, LocalizedError {
        case invalidUrl
        case noData
        
        var errorDescription: String? {
            switch self {
            case .invalidUrl: return "无效的URL地址"
            case .noData: return "未获取到数据"
            }
        }
    }
}

2. 修正Event模型的解码逻辑

针对event_chargable_or_not字段的字符串/空值情况,自定义解码逻辑:

struct Event: Codable, Identifiable {
    var id: String
    var title: String
    var startDate: Date
    var endDate: Date
    var imageURL: URL?
    var isChargeable: Bool? // 改为可选类型处理null情况
    
    enum CodingKeys: String, CodingKey {
        case id = "event_id"
        case title = "event_title"
        case startDate = "event_start_date"
        case endDate = "event_end_date"
        case imageURL = "event_img"
        case isChargeable = "event_chargable_or_not"
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        id = try container.decode(String.self, forKey: .id)
        title = try container.decode(String.self, forKey: .title)
        startDate = try container.decode(Date.self, forKey: .startDate)
        endDate = try container.decode(Date.self, forKey: .endDate)
        imageURL = try container.decodeIfPresent(URL.self, forKey: .imageURL)
        
        // 处理字段的字符串/空值逻辑
        if let chargeableStr = try container.decodeIfPresent(String.self, forKey: .isChargeable) {
            isChargeable = chargeableStr == "1"
        } else {
            isChargeable = nil
        }
    }
}

3. 其他优化点

  • 解码失败时打印详细错误信息,而非仅本地化描述,便于定位具体字段的解析问题。
  • 给DateFormatter指定固定locale,避免不同地区的日期格式解析差异。

测试验证

修改完成后,切换Upcoming或Past标签页时,即可正确获取并解析API数据,显示事件标题。若仍有问题,可通过控制台打印的原始JSON和解码错误详情继续排查。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:07:08