How to receive subitems data from a plist?

1

Good! I am having difficulty receiving subitems data from my plist. Watch ... This is my directory.plist :

IwanttoplayallthishereinthisMain.storyboard:

SincethePositionandNamekeyswillbeinthefirstTableViewControllerandtheFunctionary,ImageFace,andPhonekeyswillbeinthesecondTableViewController.

ForthisIdidthefollowing:

  • IaddedthefollowingtoAppDelegate:

    funcapplication(_application:UIApplication,didFinishLaunchingWithOptionslaunchOptions:[UIApplicationLaunchOptionsKey:Any]?)->Bool{ifleturl=Bundle.main.url(forResource:"directory", withExtension: "plist"), let array = NSArray(contentsOf: url) as? [[String:Any]] {
            Shared.instance.employees = array.map{Employee(dictionary: $0)}
    }
    return true
    
  • My Struct looks like this:

    struct EmployeeDetails {
        let functionary: String
        let imageFace: String
        let phone: String
    
        init(dictionary: [String: Any]) {
            self.functionary = (dictionary["Functionary"] as? String) ?? ""
            self.imageFace = (dictionary["ImageFace"] as? String) ?? ""
            self.phone = (dictionary["Phone"] as? String) ?? ""
        }
    }
    
    struct Employee {
        let position: String
        let name: String
        let details: [EmployeeDetails] // [String:Any]
    
        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])})
        }
    }
    
    struct Shared {
        static var instance = Shared()
        var employees: [Employee] = []
    }
    
  • My First TableViewController , looks like this:

    class Page1: UITableViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        let anEmployee = Shared.instance.employees[1]
    
        print("Name:", anEmployee.name)
        print("Position:", anEmployee.position)
    
        anEmployee.details.forEach({
    
            print("Functionary:", $0.functionary)
            print("ImageFace:", $0.imageFace)
            print("Phone:", $0.phone)
        })
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
    return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return Shared.instance.employees.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell1
    
            cell.nameLabel.text = Shared.instance.employees[indexPath.row].name
            cell.positionLabel.text = Shared.instance.employees[indexPath.row].position
    
            return cell
        }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let destination = segue.destination as? Page2,
            let indexPath = tableView.indexPathForSelectedRow {
            destination.newPage = Shared.instance.employees[indexPath.row].details[indexPath.row]
            tableView .deselectRow(at: indexPath, animated: true)
            }
        }
    }
    
  • My second TableViewController , looks like this:

    var newPage: EmployeeDetails! //recently added
    
    class Page2: UITableViewController {
    
    var newPage: EmployeeDetails!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        if let theEmployee = newPage {
            self.title = theEmployee.name
        }
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let theEmployee = newPage {
            return theEmployee.details.count
        }
    return 0
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell2
    
        if let theEmployee = newPage {
    
            cell.faceImage.image = theEmployee.details[indexPath.row].imageFace as? UIImage // did not work
            cell.functionary.text = theEmployee.details[indexPath.row].functionary
            cell.phoneLabel.text = theEmployee.details[indexPath.row].phone
        }
        return cell
        }
    }
    
  • After the changes, the project no longer has any errors, however the 2nd TableViewController remains empty! The Debug Area says the following:

    2017-03-28 17:16:28.456 plist sample[7138:425253] Unknown class Page2 in Interface Builder file.
    

    Any ideas?

    Thanks in advance.

        
    asked by anonymous 27.03.2017 / 22:16

    1 answer

    3

    Hello,

    I believe your first problem ( "Está retornando nil" ) is that the details property in your struct Employee is a dictionary of type [String:Any] , but in your .plist it is an array of dictionaries. So the correct one would be [[String:Any]] .

    Your second problem is related to the first, because if details is an array, it does not have the subscript you reference (which generates this compile error ).

    So, the correct syntax for you to extract the field value of your .plist (as it is, ipsis literis ) would be (example):

    cell.faceImage.image = Shared.instance.employees[indexPath.row].details[<!INDEX!>]["ImageFace"]
    

    Replace <!INDEX!> with the correct index.

    UPDATE

    To send the selected object in its first VC to the second VC, you must implement both func prepare(for segue: UIStoryboardSegue, sender: Any?) and func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) methods.

    Examples:

    1) When selecting a table cell:

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let object = Shared.instance.employees[indexPath.row]
        self.performSegue(withIdentifier: "ID_DA_SEGUE_AQUI", sender: object)
    }
    

    2) Load the next table with the selected data:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if  let proximoVc = segue.destination as?  {
            proximoVc.newPage = sender as? EmployeeDetails
        }
    }
    

    Note: The above code can generate a crash if the search index within the array is not correct. Make sure the references are correct before proceeding.

        
    28.03.2017 / 20:09