Swift: Cocoa binding value to a computed property does not work

你离开我真会死。 提交于 2020-01-04 06:17:07

问题


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 of NSWindowController, 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!