简体   繁体   中英

Populate NSTableView with struct

I´m trying to populate a NSTableView with a struct. The struct is getting it's data from Firebase. I have tried to replicate the way I would do it in iOS but I'm not quite there yet.

var orders = [OrderModel]()

struct OrderModel {
    var order: String!
    var name: String?
    var adress: String?
    var email: String?
}    

Read from Firebase:

ref?.child("orders").observe( .childAdded, with: { (snapshot) in
            let dict = snapshot.value as? [String : AnyObject] ?? [:]
            
            let newData = OrderModel(order: dict["order"] as? String, name: dict["name"] as? String, adress: dict["adress"] as? String, email: dict["email"] as? String
            
            self.orders.append(newData)
            })    
    

Populate the NSTableView :

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
            guard let userCell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "ordersCell"), owner: self) as? OrdersTableViewCell else { return nil }
        
        //the object
        let order: OrderModel
        
        //getting the object of selected position
        order = orders[row] //Error index out of range
        
        userCell.orderLabel.stringValue = order.order ?? "Error getting order"
        userCell.nameLabel.stringValue = order.name ?? "Error getting name"
        userCell.adressLabel.stringValue = order.adress ?? "Error getting address"
         return userCell
        }    

I don't know if the only problem here is this line:

order = orders[row] //Error index out of range

But that is where I'm at now.

Unlike in iOS in macOS there is a more sophisticated way to populate a table view: Cocoa Bindings. As you are using only one cell view for all data this is preferable.

  • First make your struct a class inheriting from NSObject

     @objcMembers class OrderModel : NSObject { dynamic var order: String? dynamic var name: String? dynamic var adress: String? dynamic var email: String? init(order : String?, name : String?, adress : String?, email : String?) { self.order = order self.name = name self.adress = adress self.email = email } }
  • Delete the entire method tableView: viewFor: row:

  • Adopt NSTableViewDataSource and NSTableViewDelegate in the view controller

  • Implement these two methods in the view controller

     func numberOfRows(in tableView: NSTableView) -> Int { return orders.count } func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { return orders[row] }
  • Select the storyboard or xib in the project navigator

  • Remove the identifier of the table cell view

  • Select the table view (not the scroll view!), press ⌥⌘7 to open the Connections Inspector and connect (control-drag) dataSource and delegate to the view controller

  • Select the Order text field in the table cell view. Make sure it is the text field.

  • Press ⌥⌘8 to open the Bindings Inspector

  • Click on the disclosure triangle next to Value

  • Check Bind To -> Table Cell View

  • In Model Key Path enter objectValue.order

  • Do the same in the other text fields (replace order with the other properties respectively)

  • In the view controller after receiving the data from Firebase reload the table view inside the closure on the main thread

    self.orders.append(newData) DispatchQueue.main.async { self.tableView.reloadData() }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM