Home > Enterprise >  SwiftUI: Having a plist to display
SwiftUI: Having a plist to display

Time:04-10

I am trying to read a plist and having it displayed as a List on SwiftUI. It compiles with no errors or warnings, but nothing gets displayed. I am not sure what I am doing wrong or the mistake I am making here. I've tried multiple things, but I still get a blank display.


import Foundation

struct PresidentModel: Decodable{
    var Name: String
    var Number: Int
    var StartDate: String
    var EndDate: String
    var Nickname: String
    var PoliticalParty: String
    
    
    enum CodingKeys: String, CodingKey{
        case Name = "Name"
        case Number = "Number"
        case StartDate = "Start Date"
        case EndDate = "End Date"
        case Nickname = "Nickname"
        case PoliticalParty = "Political Party"
    }
}

class PresidentViewModel: ObservableObject{
    @Published var PresArray: [PresidentModel] = []
    @Published var name: String = ""
    @Published var number: Int = 0
    @Published var startDate: String = ""
    @Published var endDate: String = ""
    @Published var nickname: String = ""
    @Published var politicalParty: String = ""
    
    
    func loadProperityListData(){
        guard let path = Bundle.main.path(forResource: "presidents", ofType: "plist"), let xml = FileManager.default.contents(atPath: path) else {
            fatalError("Unable to access property list states.plist")
        }
        
        do{
            PresArray =  try PropertyListDecoder().decode([PresidentModel].self, from: xml)
            name = PresArray[0].Name
            number = PresArray[0].Number
            startDate = PresArray[0].StartDate
            endDate = PresArray[0].EndDate
            nickname = PresArray[0].Nickname
            politicalParty = PresArray[0].PoliticalParty
        }
        
        catch {
            fatalError("Unable to decode property list states.plist")
        }
    }//func
}//class

Where the plist will be displayed as a List :

import SwiftUI

struct ContentView: View {
    
    let presidents = PresidentViewModel()
    
    var body: some View {
    
        List(presidents.PresArray.indices, id: \.self){ president in
            Text(presidents.PresArray[].Name)
        }
    }//Body
}//View
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

CodePudding user response:

First of all please conform to the naming convention and declare the struct member names with starting lowercase letters and add an id property

struct PresidentModel: Decodable, Identifiable {
    let id = UUID()
    let name: String
    let number: Int
    let startDate: String
    let endDate: String
    let nickname: String
    let politicalParty: String
    
    private enum CodingKeys: String, CodingKey {
        case name = "Name"
        case number = "Number"
        case startDate = "Start Date"
        case endDate = "End Date"
        case nickname = "Nickname"
        case politicalParty = "Political Party"
    }
}

The main problem is that you don't load the data, a good place is the init method of the observable class. The properties are not needed because the array contains all data

class PresidentViewModel: ObservableObject{
    @Published var presArray: [PresidentModel] = []

   init() {
      loadProperityListData()
   }
    
    func loadProperityListData(){
        guard let url = Bundle.main.url(forResource: "presidents", withExtension: "plist"), 
              let data = try? Data(contentsOf: url) else {
            fatalError("Unable to access property list states.plist")
        }
        
        do {
            presArray =  try PropertyListDecoder().decode([PresidentModel].self, from: data)
        } catch {
            print(error)
            presArray = []
        }
    }//func
}//class

The second main problem is that PresidentViewModel is not declared as @StateObject. And due to the added id property you get rid of dealing with indices and specifying id: \.self

import SwiftUI

struct ContentView: View {
    
    @StateObject var model = PresidentViewModel()
    
    var body: some View {
    
        List(model.presArray) { president in
            Text(president.name)
        }
    }//Body
}//View
  • Related