Swift中如何解析API返回的非数组JSON?代码问题求助
解决单对象JSON解析与ViewModel适配问题
核心问题
你当前ViewModel中hotelViewModel的类型是[String: String],但API返回的是单个Hotel对象,并非字符串字典,类型不匹配导致无法完成赋值。
修正步骤
调整ViewModel的Published属性类型
将@Published var hotelViewModel: [String: String] = [:]替换为:@Published var hotel: Hotel?使用可选类型是因为初始状态下无数据,请求完成后再赋值实际对象。
修复解码错误处理逻辑
原代码用try?会隐藏解码失败的真实原因,应直接用try让错误正常抛出:let hotel = try decoder.decode(Hotel.self, from: res.data)这样解码失败时会抛出
DecodingError,便于排查字段不匹配等实际问题,而非错误抛出URLError(.badURL)。修正赋值逻辑
在sink的receiveValue闭包中,将解析后的对象赋值给正确的属性:self?.hotel = returnedHotel
完整修正后的ViewModel代码
import Foundation import SwiftUI import Combine class HotelViewModel: ObservableObject { @Published var hotel: Hotel? private var bag = Set<AnyCancellable>() func fetchHotel() { let urlString = "https://run.mocky.io/v3/35e0d18e-2521-4f1b-a575-f0fe366f66e3" guard let url = URL(string: urlString) else { print("🤬ERRRROOOOOOORRRRRR") return } URLSession .shared .dataTaskPublisher(for: url) .receive(on: DispatchQueue.main) .tryMap { res in guard let response = res.response as? HTTPURLResponse, response.statusCode >= 200 && response.statusCode < 300 else { throw URLError(.badServerResponse) } let decoder = JSONDecoder() let hotel = try decoder.decode(Hotel.self, from: res.data) return hotel } .sink { completion in switch completion { case .finished: print("AllGood") case .failure(let error): print(error.localizedDescription) } } receiveValue: { [weak self] returnedHotel in self?.hotel = returnedHotel } .store(in: &bag) } }
视图层使用示例
在SwiftUI视图中,通过@StateObject引用ViewModel,可选绑定hotel属性展示数据:
struct HotelView: View { @StateObject private var viewModel = HotelViewModel() var body: some View { VStack(spacing: 16) { if let hotel = viewModel.hotel { Text(hotel.name) .font(.title) Text(hotel.adress) .font(.subheadline) Text("评分:\(hotel.rating) - \(hotel.ratingName)") // 其他酒店信息展示... } else { ProgressView() .onAppear { viewModel.fetchHotel() } } } .padding() } }
内容的提问来源于stack exchange,提问作者Константин
相关产品推荐
相关产品推荐

