Search code examples
swiftplistnstableview

Want open a plist in NStableview


I've been trying to display a plist file in NSTableView for days. I've read a lot, but so far only found instructions for iOS. My problem is that the individual values ​​are not displayed individually in the NStableView. Only the whole plist file in a cell is always displayed.

I hope someone can help me, because I just can not get any further. I'm still a freshman in Swift.

I uploaded my Plist, if someone can explain me where the error lies.

https://www.dropbox.com/s/1t8c4uldwdtp3wk/Archiv.zip?dl=0

import Cocoa


class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {

@IBOutlet weak var tableView: NSTableView!

@IBOutlet weak var ntext: NSTextField!
@IBOutlet weak var schwarztext: NSTextField!
@IBOutlet weak var cyantext: NSTextField!
@IBOutlet weak var magentatext: NSTextField!
@IBOutlet weak var gelbtext: NSTextField!
@IBOutlet weak var lightcyantext: NSTextField!
@IBOutlet weak var lightmtext: NSTextField!

var n : String? = nil; // n
var schwarz : String? = nil; // Schwarz
var cyan : String? = nil; // Cyan
var magenta : String? = nil; // Magenta
var gelb : String? = nil; // Gelb
var lightc : String? = nil; // Light Cyan
var lightm : String? = nil; // Light Magenta

let AUTO_PLIST_JOBS_PATH = Bundle.main.path(forResource: "Jobs", ofType: "plist")

let AUTO_PLIST_JOBS_KEY_N = "n"   // n
let AUTO_PLIST_JOBS_KEY_SCHWARZ = "schwarz"   // Schwarz
let AUTO_PLIST_JOBS_KEY_CYAN = "cyan"   // Cyan
let AUTO_PLIST_JOBS_KEY_MAGENTA = "magenta"   // Magenta
let AUTO_PLIST_JOBS_KEY_GELB = "gelb"   // Gelb
let AUTO_PLIST_JOBS_KEY_LIGHTC = "lightc"   // Light Cyan
let AUTO_PLIST_JOBS_KEY_LIGHTM = "lightm"   // Light Magenta

var _jobss = [Jobs]()

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.delegate = self
    tableView.dataSource = self

    // Do any additional setup after loading the view.


}

func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {

    //let path = Bundle.main.path(forResource: "Jobs", ofType: "plist")
    //let myJobs100 = NSArray(contentsOfFile: path!)
    //return myJobs100


    let path = Bundle.main.path(forResource: "Jobs", ofType: "plist")
    let url = URL(fileURLWithPath: path!)
    let data = try! Data(contentsOf: url)
    let plist = try! PropertyListSerialization.propertyList(from: data, options: .mutableContainers, format: nil)

    let dictArray = plist as! [[String:String]]
    return dictArray
}


func allJobss() -> [Jobs]{

    if _jobss.count > 0 {
        return _jobss
    }

    if let allDatas = NSArray(contentsOfFile: AUTO_PLIST_JOBS_PATH!) {

        for dict in allDatas {
            guard let dict = dict as? [String: AnyObject] else {continue}

            let jobs = Jobs()
            jobs.n = dict[AUTO_PLIST_JOBS_KEY_N] as? String // n
            jobs.schwarz = dict[AUTO_PLIST_JOBS_KEY_SCHWARZ] as? String // Schwarz
            jobs.cyan = dict[AUTO_PLIST_JOBS_KEY_CYAN] as? String // Cyan
            jobs.magenta = dict[AUTO_PLIST_JOBS_KEY_MAGENTA] as? String // Magenta
            jobs.gelb = dict[AUTO_PLIST_JOBS_KEY_GELB] as? String // Gelb
            jobs.lightc = dict[AUTO_PLIST_JOBS_KEY_LIGHTC] as? String // Light Cyan
            jobs.lightm = dict[AUTO_PLIST_JOBS_KEY_LIGHTM] as? String // Light Magenta
            _jobss.append(jobs)
        }
    }
    return _jobss
}



func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
    return 80
}

func numberOfRows(in tableView: NSTableView) -> Int {
    return allJobss().count
}

func tableViewSelectionDidChange(_ notification: Notification) {
    print(tableView.selectedRow)

    let path = Bundle.main.path(forResource: "Jobs", ofType: "plist")
    let url = URL(fileURLWithPath: path!)
    let data = try! Data(contentsOf: url)
    let plist = try! PropertyListSerialization.propertyList(from: data, options: .mutableContainers, format: nil)

    let dictArray = plist as! [[String:String]]
    // [[String:String]] is equivalent to Array< Dictionary<String, String> >

    print(dictArray[tableView.selectedRow]["n"] as Any)



}



override var representedObject: Any? {
    didSet {
    // Update the view, if already loaded.
    }
}

}

NSTableview

Plist

I hope someone can help me.


Solution

  • First of all this is Swift. Variable names including underscore characters are ugly and objective-c-ish.

    Your workflow is wrong. objectValueFor is called very often (once for each row) and is supposed to return just the object for the given row/column. Reading the same data again and again is horrible.

    Load the data once in viewDidLoad and decode the Plist directly into a class. A class is required to be able to bind the values

    @objcMembers
    class Job : NSObject, Decodable {
        dynamic var n, schwarz, cyan, magenta, gelb, lightc, lightm : String
    }
    

    @objc dynamic var jobs = [Job]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
    
        // Do any additional setup after loading the view.
        let url = Bundle.main.url(forResource: "Jobs", withExtension: "plist")!
        let data = try! Data(contentsOf: url)
        jobs = try! PropertyListDecoder().decode([Job].self, from: data)
        tableView.reloadData()
    }
    

    In objectValueFor just return the item for the row

    func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
         return jobs[row]
    }
    

    the other delegate methods are

    func numberOfRows(in tableView: NSTableView) -> Int {
        return jobs.count
    }
    
    func tableViewSelectionDidChange(_ notification: Notification) {
        let selectedRow = tableView.selectedRow
        if selectedRow == -1 {
           print("Nothing selected")
        } else {
          print("Row \(selectedRow) selected")
        }
    }
    

    You have to bind the values to text fields. Open Interface Builder, ⌃⇧-click on the left-most text field (Table View Cell) in the table view, select Table View Cell, press ⌥⌘7 to open the Bindings Inspector, click on the disclosure triangle below Value, Check the checkbox Bind to Table Cell View, in the Model Key Path text field write objectValue.n. Bind the other text fields in the row to the corresponding properties (objectValue.schwarz etc.).


    You can delete

    var n : String? = nil; // n
    var schwarz : String? = nil; // Schwarz
    var cyan : String? = nil; // Cyan
    var magenta : String? = nil; // Magenta
    var gelb : String? = nil; // Gelb
    var lightc : String? = nil; // Light Cyan
    var lightm : String? = nil; // Light Magenta
    
    let AUTO_PLIST_JOBS_PATH = Bundle.main.path(forResource: "Jobs", ofType: "plist")
    
    let AUTO_PLIST_JOBS_KEY_N = "n"   // n
    let AUTO_PLIST_JOBS_KEY_SCHWARZ = "schwarz"   // Schwarz
    let AUTO_PLIST_JOBS_KEY_CYAN = "cyan"   // Cyan
    let AUTO_PLIST_JOBS_KEY_MAGENTA = "magenta"   // Magenta
    let AUTO_PLIST_JOBS_KEY_GELB = "gelb"   // Gelb
    let AUTO_PLIST_JOBS_KEY_LIGHTC = "lightc"   // Light Cyan
    let AUTO_PLIST_JOBS_KEY_LIGHTM = "lightm"   // Light Magenta
    
    func allJobss() -> [Jobs]{
    
        if _jobss.count > 0 {
            return _jobss
        }
    
        if let allDatas = NSArray(contentsOfFile: AUTO_PLIST_JOBS_PATH!) {
    
            for dict in allDatas {
                guard let dict = dict as? [String: AnyObject] else {continue}
    
                let jobs = Jobs()
                jobs.n = dict[AUTO_PLIST_JOBS_KEY_N] as? String // n
                jobs.schwarz = dict[AUTO_PLIST_JOBS_KEY_SCHWARZ] as? String // Schwarz
                jobs.cyan = dict[AUTO_PLIST_JOBS_KEY_CYAN] as? String // Cyan
                jobs.magenta = dict[AUTO_PLIST_JOBS_KEY_MAGENTA] as? String // Magenta
                jobs.gelb = dict[AUTO_PLIST_JOBS_KEY_GELB] as? String // Gelb
                jobs.lightc = dict[AUTO_PLIST_JOBS_KEY_LIGHTC] as? String // Light Cyan
                jobs.lightm = dict[AUTO_PLIST_JOBS_KEY_LIGHTM] as? String // Light Magenta
                _jobss.append(jobs)
            }
        }
        return _jobss
    }