Load data from a plist to two TableViews

I am having some trouble to load some data from my property list. Take a look…
This is my directory.plist:
directory.plist

I wanna show all of this, right here on Main.storyboard:
Main.storyboard

  • Can I hook when a weakly-referenced object (of arbitrary type) is freed?
  • Upload Google Cloud Storage iOS
  • Get pixel data as array from UIImage/CGImage in swift
  • How do I make a UISwitch under iOS 7 not take the background colour of the view behind it?
  • Still not optimized for iPhone 6 and iPhone 6 Plus
  • draw line between two points in iphone?
  • But the keys Position e Name will appear on the first TableViewController and the keys Functionary, ImageFace and Phone have to appear on the second TableViewController.

    To do this, I made this:

    1. Added to AppDelegate the following:

      func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
          if let url = 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
      
    2. Created a Struct 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] = []
      }
      
    3. My First TableViewController, is 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)
              }
          }
      }
      
    4. My Second TableViewController, here:

      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
          }
      }
      

    When I touch in any item of the first TableViewController, I see the second TableViewController totally empty! And the debug area shows it:

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

    Solutions Collect From Internet About “Load data from a plist to two TableViews”

    According to your plist structure:

    Shared.instance.employees[indexPath.row].details
    

    details is an Array of Dictionaries. You are treating it as a Dictionary.

    Edit: the initial issue was correct… multiple ways to solve it (as you have seen / done). Another option, which may or may not be helpful:

    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] = []
    }
    

    you can then do your original:

        if let url = Bundle.main.url(forResource: "directory", withExtension: "plist"), let array = NSArray(contentsOf: url) as? [[String:Any]] {
    
            Shared.instance.employees = array.map{Employee(dictionary: $0)}
    
        }
    

    and then access the data via:

        let anEmployee = Shared.instance.employees[0]
    
        print("Name:", anEmployee.name)
        print("Position:", anEmployee.position)
    
        print("Detail 0 Functionary:", anEmployee.details[0].functionary)
        print("Detail 0 ImageFace:", anEmployee.details[0].imageFace)
        print("Detail 0 Phone:", anEmployee.details[0].phone)
    
        // or
    
        anEmployee.details.forEach({
    
            print("Functionary:", $0.functionary)
            print("ImageFace:", $0.imageFace)
            print("Phone:", $0.phone)
    
        })
    

    just for example.

    See https://github.com/DonMag/SWPListData for a working example.