Search code examples
xcodeswiftcocoaswift2cocoa-bindings

NSTextFields using bindings not updating after initialization


I am importing data from JSON to be used as the models for some items in a CollectionView, and it seems that they are being initialized, and with the correct number of elements. But for some reason the representedObject (aliased as morpheme below) is returning nil initially. Hence the placeholder if nil values being the ones showing up.

If you click the items, I have it set up to show up in the log the name of the item clicked, and it works fine, and doesn't return the debugging defaults. So I'm guessing there is a concurrency issue going on.

For more details, this are items being manually prototyped because XCode 7 still hasn't fixed the segue bug with collection item prototypes.

Here is a screenshot I hopefully managed to get it all the important info in:

enter image description here

Here is the cell's controller/delagating class code in detail:

///Acts as view controller for the items of the morpheme collection
public class MorphemeCell: NSCollectionViewItem, NSTextViewDelegate{

    var backgroundColor = NSColor.clearColor()

    var morphemeLabel: String{
        get{
            return morpheme?.morphemeDisplayName ?? "Morpheme"
        }
    }

    var allomorphsLabel: String{
        get{
            return (morpheme?.allomorphsAsString ?? "Allomorphs")
        }
    }

    ///The morpheme data contained in the cell
    public var morpheme : Morpheme?{
        get{
            return representedObject as? Morpheme
        }
        set{
            representedObject = newValue
        }
    }

    required public init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    ///Detects clicks on each item
    public override func mouseUp(theEvent: NSEvent) {
        Swift.print("Clicked on " + morphemeLabel)
        backgroundColor = NSColor.blueColor()
    }
}

Not sure if this is needed, but just in case here is the main window's ViewController doing some setup/loading functionality.

enter image description here

The loading code itself:

///Loads morpheme data into memory and then into the collection view
func loadMorphemeData(){
    //Open morphemes.json and begin parsing
    let morphemeDataPath = "morphemes"
    if let file = NSBundle.mainBundle().URLForResource(morphemeDataPath, withExtension: "json")
    {
        let data = NSData(contentsOfURL: file)
        let json = JSON(data:data!)

        //Create Morpheme objects passing in JSON elements
        for morphemeElement in json{
            let toAdd = Morpheme(JSONElement: morphemeElement)
            fullMorphemesList.append(toAdd)
        }
        ///TODO Use full range or filters in final product
        let morphemesToLoad = fullMorphemesList[0...100]
        collectionView.content.appendContentsOf(Array(morphemesToLoad) as [AnyObject])
    }
    else
    {
        print("Resource Failure")
    }

So, recap: It seems that I either need to delay the collectionView's setup, or find out how to update the Labels once the data is in. Thanks very much for any help! I'm very new to the Cocoa framework so it's been a doozy.


Solution

  • Take different route: bind your label to self.morpheme.morphemeDisplayName. Then set "Null Placeholder" text to be "Morpheme" (in that right panel see the list of text edits below binding settings). Finally make property morphemeDisplayName dynamic:

     dynamic var morphemeDisplayName: String? 
    

    Obviously, you dont need morphemeLabel property inside cell anymore.

    morpheme property of cell must be dynamic as well, or if there is setter-based property, you can call:

     set {
     willChangeValueForKey("morpheme") 
     <whatever variable> = newValue 
     didChangeValueForKey("morpheme") 
     }
    

    Edit by original poster:

    Also, in order to avoid binding synchrony issues, it turns out using viewWillAppear() instead of viewDidLoad() was causing issues with data loading and "freezing the labels".