SwiftUI中如何基于业务段ID关联解析对应公司JSON数据?
SwiftUI JSON解析与业务段关联公司展示问题
我是SwiftUI新手,目前已能读取完整JSON数据,但需要实现以下功能:在ContentView中生成对应6个业务段的按钮,点击按钮跳转至CompanyName View,仅展示该业务段关联ID对应的公司(而非全部公司)。附上相关文件代码寻求解决方案。
JSON文件内容
{ "client": { "id": 200, "first_name": "Luke", "last_name": "", "email": "luke@abc.com" }, "business_segments": [ { "id": 1, "name": "Segment A", "status": "Open", "companies": [5,6,7] }, { "id": 2, "name": "Segment B", "status": "Open", "companies": [1,2,4] }, { "id": 3, "name": "Segment C", "status": "Open", "companies": [3,8,12] }, { "id": 4, "name": "Segment D", "status": "Open", "companies": [9,10,15] }, { "id": 5, "name": "Segment E", "status": "Open", "companies": [11,13,14,16] }, { "id": 6, "name": "Segment F", "status": "Open", "companies": [17,18] } ], "companies": [ { "id": 1, "name": "COMPANY A", "status": "Open" }, { "id": 2, "name": "COMPANY B", "status": "Open" }, { "id": 3, "name": "COMPANY C", "status": "Open" }, { "id": 4, "name": "COMPANY D", "status": "Open" }, { "id": 5, "name": "COMPANY E", "status": "Open" }, { "id": 6, "name": "COMPANY F", "status": "Open" }, { "id": 7, "name": "COMPANY G", "status": "Open" }, { "id": 8, "name": "COMPANY H", "status": "Open" }, { "id": 9, "name": "COMPANY I", "status": "Open" }, { "id": 10, "name": "COMPANY J", "status": "Open" }, { "id": 11, "name": "COMPANY K", "status": "Open" }, { "id": 12, "name": "COMPANY L", "status": "Open" }, { "id": 13, "name": "COMPANY M", "status": "Open" }, { "id": 14, "name": "COMPANY N", "status": "Open" }, { "id": 15, "name": "COMPANY O", "status": "Open" }, { "id": 16, "name": "COMPANY P", "status": "Open" }, { "id": 17, "name": "COMPANY Q", "status": "Open" }, { "id": 18, "name": "COMPANY R", "status": "Open" } ] }
CompanyViewModel.swift代码
import Foundation // MARK: - CompanyData struct CompanyData: Codable, Hashable { let client: Client let businessSegments: [BusinessSegment] let companies: [Company] enum CodingKeys: String, CodingKey { case client case businessSegments = "business_segments" case companies } } // MARK: - BusinessSegment struct BusinessSegment: Codable, Hashable { let id: Int let name: String let status: Status let companies: [Int]? } enum Status: String, Codable { case open = "Open" } // MARK: - Client struct Client: Codable, Hashable { let id: Int let firstName, lastName, email: String enum CodingKeys: String, CodingKey { case id case firstName = "first_name" case lastName = "last_name" case email } } // 匹配JSON的公司结构体 struct Company: Codable, Hashable { let id: Int let name: String let status: Status } class CompanyViewModel: ObservableObject{ @Published var companyData: CompanyData? func getUserData(){ guard let url = Bundle.main.url(forResource:"Company", withExtension:"json") else { print("无效URL") return } let task = URLSession.shared.dataTask(with:url){ data, response, error in let decoder = JSONDecoder() if let data = data { do { let companyData = try decoder.decode(CompanyData.self, from:data) DispatchQueue.main.async{ self.companyData = companyData } } catch { print("解析失败: \(error)") print(String(data:data, encoding:.utf8) ?? "无法打印数据") } } } task.resume() } // 根据业务段过滤对应公司 func getCompaniesForSegment(_ segment: BusinessSegment) -> [Company] { guard let allCompanies = companyData?.companies, let segmentCompanyIds = segment.companies else { return [] } return allCompanies.filter { segmentCompanyIds.contains($0.id) } } }
ContentView.swift代码
import SwiftUI struct ContentView: View { @StateObject private var companyVM = CompanyViewModel() var body: some View { NavigationStack { VStack(spacing: 16) { if let companyData = companyVM.companyData { ForEach(companyData.businessSegments, id: \.id) { segment in NavigationLink(destination: CompanyName(segment: segment, companyVM: companyVM)) { Text(segment.name) .frame(width:240,height:50) .bold() .foregroundColor(.white) .background(Color.orange) .clipShape(Capsule()) } } } else { ProgressView("加载中...") } } .padding() .onAppear(){ companyVM.getUserData() } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
CompanyName.swift代码
import SwiftUI struct CompanyName: View { let segment: BusinessSegment @ObservedObject var companyVM: CompanyViewModel var body: some View { NavigationStack { VStack(spacing: 16) { Text(segment.name) .multilineTextAlignment(.center) .bold() .font(.custom("Montserrat-Bold", size: 24)) let filteredCompanies = companyVM.getCompaniesForSegment(segment) if filteredCompanies.isEmpty { Text("暂无关联公司") .font(.title3) .foregroundColor(.gray) } else { ForEach(filteredCompanies, id: \.id) { company in Text(company.name) .multilineTextAlignment(.center) .bold() .font(.custom("Montserrat-Bold", size: 20)) .padding(.vertical, 8) } } } .padding() .navigationTitle("关联公司") } } } struct CompanyName_Previews: PreviewProvider { static var previews: some View { let testSegment = BusinessSegment(id: 1, name: "Segment A", status: .open, companies: [5,6,7]) let vm = CompanyViewModel() vm.companyData = CompanyData(client: Client(id: 200, firstName: "Luke", lastName: "", email: "luke@abc.com"), businessSegments: [testSegment], companies: [Company(id:5, name: "COMPANY E", status: .open), Company(id:6, name: "COMPANY F", status: .open), Company(id:7, name: "COMPANY G", status: .open)]) return CompanyName(segment: testSegment, companyVM: vm) } }
关键修改说明
- 修复数据模型错误:原
CompanyData中companies类型错误,新增Company结构体匹配JSON字段,保证解析正确性。 - 优化ViewModel结构:将
company_data从数组改为单个可选对象,新增业务段公司过滤方法,直接复用已加载的数据。 - 统一ViewModel实例:
CompanyName接收ContentView传递的ViewModel,避免重复加载JSON,保证数据一致。 - 更新导航组件:用
NavigationStack替代过时的NavigationView,适配新版iOS系统。 - 稳定的列表标识:用对象
id作为ForEach的唯一标识,比\.self更可靠。
内容的提问来源于stack exchange,提问作者Luke Louyu
相关产品推荐
相关产品推荐

