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

SwiftUI解码PHP JSON API并在ScrollView显示文本的问题

SwiftUI JSON解码与数据展示问题修复方案

核心问题梳理

  • 结构体解码逻辑错误:原CallData错误将records解码为[String:[String]],但接口返回的records是字典数组;Record未遵循Decodable协议,字段设计也未匹配JSON结构。
  • 视图与数据模型未关联:SecondTabView自行定义了gmodel数组,但未绑定ContentModel的@Published数据,导致接口数据无法传递到视图。
  • 错误处理不完善:未处理data为空、URL无效、响应状态码异常等情况,难以排查请求失败原因。

1. 修正解码结构体

严格匹配接口返回的JSON结构,使用CodingKeys处理蛇形命名到驼峰命名的映射:

// 匹配JSON根结构
struct CallData: Decodable {
    let records: [Record]
}

// 匹配单个记录的JSON结构,遵循Identifiable便于SwiftUI遍历
struct Record: Decodable, Identifiable {
    let id: String
    let stopName: String
    let stopTime: String
    
    private enum CodingKeys: String, CodingKey {
        case id = "ID"
        case stopName = "stop_name"
        case stopTime = "stop_time"
    }
}

2. 修正数据模型类(ContentModel)

完善错误处理逻辑,确保数据正确解析并更新到视图:

class ContentModel: ObservableObject {
    @Published var records = [Record]()
    
    init() {
        getData()
    }
    
    func getData() {
        guard let url = URL(string: "https://not.the.real.php?route=Green") else {
            print("无效的URL")
            return
        }
        
        var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 10)
        request.httpMethod = "GET"
        
        URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
            // 处理网络错误
            if let error = error {
                print("网络请求错误: \(error.localizedDescription)")
                return
            }
            
            // 处理数据为空的情况
            guard let data = data else {
                print("接口未返回数据")
                return
            }
            
            // 校验响应状态码
            if let httpResponse = response as? HTTPURLResponse, !(200...299).contains(httpResponse.statusCode) {
                print("接口响应错误,状态码: \(httpResponse.statusCode)")
                return
            }
            
            do {
                let decoder = JSONDecoder()
                let result = try decoder.decode(CallData.self, from: data)
                // 按ID排序(可选,根据需求调整)
                let sortedRecords = result.records.sorted { $0.id < $1.id }
                
                DispatchQueue.main.async {
                    self?.records = sortedRecords
                }
            } catch {
                print("JSON解码错误: \(error.localizedDescription)")
                print("错误详情: \(error)")
            }
        }.resume()
    }
}

3. 修正SecondTabView视图

绑定数据模型,直接遍历展示所需字段:

struct SecondTabView: View {
    @Namespace var mapScope
    // 使用@StateObject绑定数据模型,确保视图响应数据变化
    @StateObject private var model = ContentModel()
    
    var body: some View {
        VStack {
            // 展示站点名称与停留时间
            ScrollView {
                VStack(spacing: 16) {
                    ForEach(model.records) { record in
                        VStack(alignment: .leading) {
                            Text("站点名称: \(record.stopName)")
                                .font(.headline)
                            Text("停留时间: \(record.stopTime)分钟")
                                .font(.subheadline)
                                .foregroundColor(.secondary)
                        }
                        .padding(.horizontal)
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .border(.gray.opacity(0.2), cornerRadius: 8)
                        .padding(.horizontal)
                    }
                }
            }
            
            Map(scope: mapScope) {
                Marker("Here", coordinate: .Youtoo)
            }
            .mapStyle(.hybrid(elevation: .realistic))
            
            MapUserLocationButton(scope: mapScope).tint(.red)
        }
        .mapScope(mapScope)
    }
}

// 补充自定义坐标扩展(如果需要)
extension CLLocationCoordinate2D {
    static let Youtoo = CLLocationCoordinate2D(latitude: -11.11, longitude: 11.11)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 03:54:52