关于SwiftUI中基于ID号解析JSON数据的问题



我是SwiftUI的新手,在SwiftUI中从JSON文件解析数据时遇到了问题。现在,我可以在JSON文件中传递所有数据,但我想要的是基于它们的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"
}
]
}

您可以从JSON文件中看到,在我的业务部门部分,我列出了一个数字列表。这些数字是与公司部分中的特定公司相关联的id号。我希望在contentView中有六个按钮。每个按钮代表一个业务部门。当我单击每个按钮时,它将跳转到CompanyName View,其中显示与每个业务部门相关的所有公司。然而,我所能做的和我所做的是在CompanyName视图中列出所有公司。因此,我需要一些帮助。我将向您展示我的项目中的不同文件。

CompanyViewModel.swift,其中处理json中的所有解析:

import Foundation

// MARK: - CompanyData
struct CompanyData: Codable,Hashable {
let client: Client
let businessSegments, companies: [BusinessSegment]
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 statusOpen = "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
}
}

class CompanyViewModel:ObservableObject{

@Published var company_data: [CompanyData] = []

func getUserData(){

guard let url = Bundle.main.url(forResource:"Company", withExtension:"json") else {
print("Invalid URL")
return
}

let task = URLSession.shared.dataTask(with:url){ data, response, error in
let decoder = JSONDecoder()
if let data = data {
do {
let company_data = try decoder.decode(CompanyData.self, from:data)

DispatchQueue.main.async{
self.company_data = [company_data]
}

print(company_data.businessSegments)
print()
print(company_data.companies)
print()


} catch {
print("cannot decode")
print(String(data:data, encoding:.utf8) as Any)
print(error)
}
}

}

task.resume()


}
}


ContentView.swift

import SwiftUI
struct ContentView: View {
@StateObject private var companyVM = CompanyViewModel()
var body: some View {
NavigationView{
VStack {
ForEach(companyVM.company_data,id:.self){ item in
ForEach(item.businessSegments,id:.self){ segment in
/*Text(segment.name)
.multilineTextAlignment(.center)
.bold()
.font(.custom("Montserrat-Bold", size: 24)) */


NavigationLink(destination:
CompanyName(segment: segment.name)){
Text(segment.name)
.frame(width:240,height:50)
.bold()
.foregroundColor(.white)
.background(Color.orange)
.clipShape(Capsule())
}


}
}
}
.padding()
.onAppear(){
companyVM.getUserData()
}
}
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

CompanyName.swift

import SwiftUI
struct CompanyName: View {
let segment: String
@StateObject private var companyVM = CompanyViewModel()
var body: some View {
NavigationView{
VStack{
Text(segment)
.multilineTextAlignment(.center)
.bold()
.font(.custom("Montserrat-Bold", size: 24))

ForEach(companyVM.company_data,id:.self){ item in
ForEach(item.companies,id:.self){ company in
Text(company.name)
.multilineTextAlignment(.center)
.bold()
.font(.custom("Montserrat-Bold", size: 24))
}
}

}.padding()
.onAppear(){
companyVM.getUserData()
}
}
}
}
struct CompanyName_Previews: PreviewProvider {
static var previews: some View {
CompanyName(segment: "Business Segments")
}
}

下面是显示与所选细分相关的公司的代码。当您点击一个细分市场时,将检索该特定细分市场的公司(基于id)从;一个特定的CompanyData或所有的[CompanyData]。将代码调整为选择一个或另一个,两个功能都在CompanyViewModel中给出。

注意,我离开了@Published var company_data: [CompanyData],虽然你说你只有一个CompanyData在里面。

看看这个链接,它给你的例子如何使用ObservableObject和管理数据在你的应用https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app

class CompanyViewModel: ObservableObject {
@Published var company_data: [CompanyData] = []

func getUserData(){
guard let url = Bundle.main.url(forResource:"Company", withExtension:"json") else {
print("Invalid URL")
return
}
let task = URLSession.shared.dataTask(with:url){ data, response, error in
let decoder = JSONDecoder()
if let data = data {
do {
let company_data = try decoder.decode(CompanyData.self, from:data)
DispatchQueue.main.async{
self.company_data = [company_data]
}
print(company_data.businessSegments)
print()
print(company_data.companies)
print()
} catch {
print("cannot decode")
print(String(data:data, encoding:.utf8) as Any)
print(error)
}
}
}
task.resume()
}

// get all companies for a particular segment and from a particular CompanyData
func getCompaniesFor(seg: BusinessSegment, item: CompanyData) -> [BusinessSegment] {
var companies = [BusinessSegment]()
if let segCompanies = seg.companies {
for id in segCompanies {
for company in item.companies {
if company.id == id {
companies.append(company)
}
}
}
}
return companies
}

// get all companies for a particular segment from all [CompanyData]
func getAllCompaniesFor(seg: BusinessSegment) -> [BusinessSegment] {
var companies = [BusinessSegment]()
if let segCompanies = seg.companies {
company_data.forEach { company_data in
for company in company_data.companies {
for id in segCompanies {
if company.id == id {
companies.append(company)
}
}
}
}
}
return companies
}

}
struct ContentView: View {
@StateObject var companyVM = CompanyViewModel() // <-- here

var body: some View {
NavigationView{
VStack {
ForEach(companyVM.company_data){ item in
ForEach(item.businessSegments){ segment in
/*Text(segment.name)
.multilineTextAlignment(.center)
.bold()
.font(.custom("Montserrat-Bold", size: 24)) */

// --- here
NavigationLink(destination:
CompanyName(segment: segment, companyVM: companyVM)){
Text(segment.name)
.frame(width:240,height:50)
.bold()
.foregroundColor(.white)
.background(Color.orange)
.clipShape(Capsule())
}
}
}
}
.padding()
.onAppear {
companyVM.getUserData()
}
}
}
}
struct CompanyName: View {
let segment: BusinessSegment  // <-- here
@ObservedObject var companyVM: CompanyViewModel // <-- here

var body: some View {
NavigationView{
VStack{
Text(segment.name).foregroundColor(.blue)
.multilineTextAlignment(.center)
.bold()
.font(.custom("Montserrat-Bold", size: 24))

// --- here
ForEach(companyVM.getAllCompaniesFor(seg: segment)){ company in
Text(company.name)
.multilineTextAlignment(.center)
.bold()
.font(.custom("Montserrat-Bold", size: 24))
}

}.padding()
}
}

}
// MARK: - CompanyData
struct CompanyData: Identifiable, Codable,Hashable { // <-- here
let id = UUID() // <-- here
let client: Client
let businessSegments, companies: [BusinessSegment]

enum CodingKeys: String, CodingKey {
case client, companies
case businessSegments = "business_segments"
}
}
// MARK: - BusinessSegment
struct BusinessSegment: Identifiable, Codable,Hashable { // <-- here
let id: Int
let name: String
let status: String
let companies: [Int]?
}
// MARK: - Client
struct Client: Identifiable, Codable,Hashable { // <-- here
let id: Int
let firstName, lastName, email: String

enum CodingKeys: String, CodingKey {
case id, email
case firstName = "first_name"
case lastName = "last_name"
}
}

根据之前的回答,在等待新的回答时,我已经想出了下面的问题:代码是这样的

func getAllCompaniesFor(seg: BusinessSegment, com: [Companies]) -> [Companies] {
var companies = [Companies]()
print(companies)
if let segCompanies = seg.companies {

company_data.forEach { company_data in
for company in company_data.companies {
for id in segCompanies {
if company.id == id {
companies.append(company)
print(companies)
}
}
}
}
}
return companies
}

最新更新