Search code examples
iosarraysswiftuitableviewplist

Displaying an array of data from plist in tableview


I'm working on displaying data from a plist in multiple "drill down" tableViews. The displayed data is only going to be read-only and I don't want it to necessarily be based on web data, and there will only be a maximum of about 100 data points so I'm fairly happy with plist instead of JSON.

Anyway, the question... I've got an array of dictionary items that I'm managing to display fairly well. I started with the GitHub relating to the following question on stack overflow (I modified it a little bit but thats not important).

Load data from a plist to two TableViews

https://github.com/DonMag/SWPListData

What I need help with is displaying an array of items ("friends" in this example) under each person. Code below will hopefully explain.

I've created an empty array in the model

struct EmployeeDetails {
let functionary: String
let imageFace: String
let phone: String

//This is the new array I've added and am having trouble displaying
let friends: [String]


init(dictionary: [String: Any]) {
    self.functionary = (dictionary["Functionary"] as? String) ?? ""
    self.imageFace = (dictionary["ImageFace"] as? String) ?? ""
    self.phone = (dictionary["Phone"] as? String) ?? ""

    //I've initialised it here. 
    self.friends = (dictionary["Friends"] as? [String]) ?? [""]

Now in the viewController displaying the data. I don't have any problems at all displaying the correct data for the "functionary", "imageFace" and "phone" - but I just can't seem to display "friends" as an array in its own section. I'm pretty sure the main problem is in numberOfRows and cellForRow:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if section == 0 {
    if let theEmployee = newPage {
        return theEmployee.details.count
    }
    return 0

}
    else if section == 1 {
        return 1
    }
    else if section == 2 {
        if let theEmployee = newPage {
            return theEmployee.details.count
        }
        return 0
    }
    else {
        return 0
    }
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) // as! TableViewCell2

    if indexPath.section == 0 {

        cell.textLabel?.text = "A"

        if let theEmployee = newPage {
            cell.textLabel?.text = theEmployee.details[indexPath.row].functionary
            cell.detailTextLabel?.text = theEmployee.details[indexPath.row].phone + "  (" + theEmployee.details[indexPath.row].imageFace + ")"
        }
    }

    else if indexPath.section == 1 {
        cell.textLabel?.text = "Test"

        }

    else if indexPath.section == 2 {
        cell.textLabel?.text = ????

        }

    return cell
}

I thought it would work writing the following in numberOfRows:

else if section == 2 {
        if let theEmployee = newPage {
            return theEmployee.details.friends.count
        }
        return 0
    } 

But I get the error:

value of type '[EmployeeDetails]' has no member 'friends'.

What do I need to do to get that array?

Note: The array is not empty.

Any suggestions/help would be much appreciated!


Solution

  • Problem is that you are accessing the friends property on details whereas it is a property on the structs stored inside details so you would have to access it through indexing something like this

    theEmployee.details[yourIndex].friends.count
    

    Update:

    //First you need to make changes inside the .plist file, please go there and add Friends Array inside just like Details

    Now this will require you to change your Employee struct code

    struct Employee {
        let position: String
        let name: String
        let details: [EmployeeDetails]
        let friends: [String]
    
        init(dictionary: [String: Any]) {
     self.position = (dictionary["Position"] as? String) ?? ""
     self.name = (dictionary["Name"] as? String) ?? ""
    
     let t = (dictionary["Details"] as? [Any]) ?? []
     self.details = t.map({EmployeeDetails(dictionary: $0 as! [String : Any])})
     self.friends = (dictionary["Friends"] as? [String]) ?? []
    
        }
     }
    

    Next step would be to add this in the table view as follows

    override func numberOfSections(in tableView: UITableView) -> Int {
     return 2
        }
    
        override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    
     if let theEmployee = newPage {
     if section == 0 {
     return theEmployee.details.count
     }else if section == 1 {
     return theEmployee.friends.count
     }
    
     }
     return 0
    
        }
     override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    
     if section == 0 {
     return "Subordinates"
     }else if section == 1 {
     return "Friends"
     }
    
     return ""
     }
    
    
     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
     let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) // as! TableViewCell2
    
     cell.textLabel?.text = "A"
    
     if let theEmployee = newPage {
     if indexPath.section == 0 {
     cell.textLabel?.text = theEmployee.details[indexPath.row].functionary
     cell.detailTextLabel?.text = theEmployee.details[indexPath.row].phone + "  (" + theEmployee.details[indexPath.row].imageFace + ")"
     }else if indexPath.section == 1 {
     cell.textLabel?.text = theEmployee.friends[indexPath.row]
     }
     }
    
    
    
     return cell
        }
    
     }