问题
I am learning KVC and binding. Currently, I am trying to bind an NSTextField to a computed property colorWallStr
. I have bound the sliders' value to the corresponding color variable and also bound the value of the label to the computed property.
However, the content of the label does not change when I move the slide.
// Inside MainWindowController
dynamic var colorRed: CGFloat = 1.0
dynamic var colorGreen: CGFloat = 1.0
dynamic var colorBlue: CGFloat = 0.0
dynamic var colorWallStr: String {
get {
return "R: \(colorRed) G: \(colorGreen) B: \(colorBlue)"
}
}
It is working fine when I bond the label to the color variable directly.
Thanks @vadian's answer. Now I can update the label using property's didSet
to trigger update label method (see below).
dynamic var colorBlue: CGFloat = 0.0 {
didSet {
updateLabel()
}
}
func updateLabel() {
colorWall = "R: \(colorRed) G: \(colorGreen) B: \(colorBlue)"
}
If properties used in string interpolation don't update the enclosing computed property, then why does the following code snippet does not work?
dynamic var colorWall: String {
get {
let red = colorRed
let green = colorGreen
let blue = colorBlue
return "R: \(red) G: \(green) B: \(blue)"
}
}
回答1:
The Key-Value Observering API lets you handle situations like this by allowing you to register dependent keys. Here's how the documentation introduces the subject:
There are many situations in which the value of one property depends on that of one or more other attributes in another object. If the value of one attribute changes, then the value of the derived property should also be flagged for change.
In this situation the value of colorWallString
depends on the value of your three color variables, so all you need to do is implement a class method that makes this clear:
// It's crucial that you get the signature of this method correct,
// otherwise it'll just be ignored.
class func keyPathsForValuesAffectingColorWallStr() -> Set<NSObject> {
return Set<NSObject>(arrayLiteral: "colorRed", "colorBlue", "colorGreen")
}
As noted in the code snippet, the format of the method you use to flag up dependent keys is crucial; you can (and should) read the relevant documentation here.
回答2:
Properties used in string interpolation don't update the enclosing computed property.
You could do it this way
dynamic var colorRed: CGFloat = 1.0 { didSet { updateLabel() } }
dynamic var colorGreen: CGFloat = 1.0 { didSet { updateLabel() } }
dynamic var colorBlue: CGFloat = 0.0 { didSet { updateLabel() } }
dynamic var colorWallStr = ""
func updateLabel()
{
colorWallStr = String(format:"R: %.2f G: %.2f B: %.2f ", colorRed, colorGreen, colorBlue)
}
回答3:
For Xcode 9.0, Swift 4:
class SampleViewController: NSViewController {
@objc dynamic var colorRed: CGFloat = 1.0
@objc dynamic var colorGreen: CGFloat = 1.0
@objc dynamic var colorBlue: CGFloat = 0.0
@objc dynamic var colorWallStr: String {
get {
return "R: \(colorRed) G: \(colorGreen) B: \(colorBlue)"
}
}
override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set<String> {
switch key {
case "colorWallStr" :
return Set(["colorRed", "colorGreen", "colorBlue"])
default :
return super.keyPathsForValuesAffectingValue(forKey: key)
}
}
}
Small tips:
- Use
NSViewController
, instead ofNSWindowController
, in this case.
Further information:
- keyPathsForValuesAffecting with NSManagedObject
回答4:
“In some cases a value may be dependent on another. For example, if you have a Person class with a computed property fullName that is dependent on the properties firstName and lastName, wouldn’t it be nice if observers of fullName could be notified when either firstName or lastName changes? KVO’s designers thought so, too, which is why they implemented a convention for defining dependent keys.
To define a key’s dependencies you must implement a specially named class method which returns a Set of key paths. In the example above you would implement keyPathsForValuesAffectingFullName():
”
Excerpt From: Hillegass, Aaron. “Cocoa Programming for OS X: The Big Nerd Ranch Guide, 5/e (Big Nerd Ranch Guides).” iBooks.
来源:https://stackoverflow.com/questions/35892657/swift-cocoa-binding-value-to-a-computed-property-does-not-work