skip to Main Content

I am new to SwiftUI and have encountered problems parsing data from JSON files in SwiftUI. At now, I can pass all the data in the JSON file but what I want is to parse a list of data based on their id number.

Here is my json file:

{
  "client": {
    "id": 200,
    "first_name": "Luke",
    "last_name": "",
    "email": "[email protected]"
  },
  "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"
    }
  ]
}

As you can see from the JSON file, in my business segments section, I listed down a list of numbers. These numbers are the id number associated with the specific company in the company section. What I wish to do is have six buttons in the contentView. Each button represents one business segment. As I click on each button, it will jump to CompanyName View, where all the companies related to each business segment are shown. However, what I could do and what I have tired is to list all the companies in the CompanyName View.
Hence, I need some help. I will show you different files in my project.

CompanyViewModel.swift, where handle all the parsing from 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")
        }
    }


2

Answers


  1. Chosen as BEST ANSWER

    Based on the previous answer, I have already figured out my following question as I waited for a new response: the code is like this

     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
         }
    

  2. Here is the code that displays the companies related to the selected segment.
    As you tap a segment, the companies for that particular segment are retrieved (based on id)
    from; a particular CompanyData or from all [CompanyData]. Adjust the code to
    select one or the other, both functions are presented in the CompanyViewModel.

    Note, I left the @Published var company_data: [CompanyData],
    although you said you only have one CompanyData in it.

    Have a look at this link, it gives you examples of how to use ObservableObject and manage data in your app 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"
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search