Home > front end >  How to programatically remove a value transformer from a Binding in NSBindingOption
How to programatically remove a value transformer from a Binding in NSBindingOption

Time:06-24

I'm binding NSValueTransformer programatically to NSTextField property on demand in a macOS application. My question is how can I remove this binding?

Relevant code snippet to bind the NSValueTransformer:

@IBOutlet var plcAddrLabel: NSTextField!

@objc dynamic var registerAddr = Int(1)

var optionsDict: [NSBindingOption : Any] = [:]

optionsDict = [NSBindingOption.valueTransformer:decToHexTransformer(), NSBindingOption.valueTransformerName:NSValueTransformerName.decToHexTransformerName]
            
plcAddrLabel.bind(.value, to: self, withKeyPath: "plcRegisterAddress" , options: optionsDict)

When it comes to unbinding I have tried a number of different approaches:

The following code

optionsDict = [NSBindingOption.valueTransformer: "<null>", NSBindingOption.valueTransformerName: "<null>"]
plcAddrLabel.bind(.value, to: self, withKeyPath: "plcRegisterAddress" , options: optionsDict)

causes this error upon execution:

-[NSTaggedPointerString transformedValue:]: unrecognized selector sent to instance 0x7b73031cc07cbe65

The reason for using "<null>" is that it is returned by plcAddrLabel.infoForBinding(.value) before binding the NSValueTransformer for the first time:

NSValueTransformer = "<null>";

NSValueTransformerName = "<null>";

I have also tried

optionsDict = [NSBindingOption.valueTransformer: NSBindingOption.nullPlaceholder, NSBindingOption.valueTransformerName: NSBindingOption.nullPlaceholder]

unfortunately the result is the same.

Interestingly plcAddrLabel.infoForBinding(.value) also shows:

NSNullPlaceholder = "<null>";

It appears, as soon as I try to remove/clear the transformer option the transformer gets called.

Note: while the transformer is bound to the NSTextfield it works fine. Replacing one transformer with another transformer also works.

Any suggestions for further diagnosis would be much appreciated.

Xcode 13.2.1

CodePudding user response:

I assume you wanted this

plcAddrLabel.unbind(.value)

CodePudding user response:

I think you're looking or NSObject.unbind(_:)

It appears, as soon as I try to remove/clear the transformer option the transformer gets called. Note: while the transformer is bound to the NSTextfield it works fine.

Could you elaborate on this?

The following code

optionsDict = [NSBindingOption.valueTransformer: "<null>", NSBindingOption.valueTransformerName: "<null>"]
plcAddrLabel.bind(.value, to: self, withKeyPath: "plcRegisterAddress" , options: optionsDict)

causes this error upon execution:

Of course it does! "<null>" is just a string, with absolutely no special semantic value in this context. It's not an NSValueTransformer, and doesn't respond to the transformedValue message.


Side note, this code doesn't make much sense:

var optionsDict: [NSBindingOption : Any] = [:]

optionsDict = [NSBindingOption.valueTransformer:decToHexTransformer(), NSBindingOption.valueTransformerName:NSValueTransformerName.decToHexTransformerName]
            
plcAddrLabel.bind(.value, to: self, withKeyPath: "plcRegisterAddress" , options: optionsDict)

You're making an empty dictionary to assign to optionsDict, but you're then immediately replacing it with a new dictionary. This causes it to be needless mutable. It could just be:

let optionsDict: [NSBindingOption : Any] = [
    NSBindingOption.valueTransformer: decToHexTransformer(),
    NSBindingOption.valueTransformerName: NSValueTransformerName.decToHexTransformerName
]

plcAddrLabel.bind(.value, to: self, withKeyPath: "plcRegisterAddress" , options: optionsDict)

Better yet, if you inlined it, the type and used some implicit member expressions, it gets even nicer:

plcAddrLabel.bind(.value, to: self, withKeyPath: "plcRegisterAddress" , options: [
    .valueTransformer: decToHexTransformer(),
    .valueTransformerName: NSValueTransformerName.decToHexTransformerName
])
  • Related