1

I'm trying to animate the image change in NSImageView. It is a purely academic problem, and I'm staying within the restrictions of a macOS binding framework.

Please, consider the model:

class Model: NSObject {
    /// Image object for the NSImageView
    @objc dynamic var image: NSImage?
    /// The target action for button `A`.
    /// Changes the image inside model.
    /// The change is not a KVO compliment because such a change is 'inside' the model.
    @objc func a() {
        self.image = NSImage(named: "a")
    }
    /// The target action for the button B
    /// In the window UI
    @objc func b() {
        self.image = NSImage(named: "b")
    }
}

enter image description here

It is the simplest and strait-forward binding example from the bible (What Are Cocoa Bindings?). The difference I want to achieve is to make the image change process visible to the user.

I will intercept every new image moving to the NSImageView from NSObjectController and transit it with the old one.

class AnimatedImageView: NSImageView {

    override func setValue(_ value: Any?, forKey key: String) {
        // The code execution is never through this point.
        if key == "image" {
            self.transition(value as! NSImage?)
        } else {
            super.setValue(value, forKey: key)
        }
    }

    private func transition(_ newImage:NSImage?) {
        let transition = CATransition()
        transition.duration = 1
        transition.type = .fade
        transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
        self.layer?.add(transition, forKey: nil)
        self.image = newImage
    }

}

The attempt to override the method setValue(_:forKey:) was not successful. Despite this, I know that the method bind(...) is firing well, and the application itself is working well, except for animation.

What I missed?

Please, find attached the project source is there.

Ruben Kazumov
  • 3,803
  • 2
  • 26
  • 39
  • What makes you expect `setValue` to be called? Or put another way: what do you think should be calling `setValue`? – Sweeper Sep 06 '21 at 05:33
  • 1
    What is the end goal? What do you wanna achieve? – Sajjon Sep 06 '21 at 05:45
  • @Sajjon I am implementing the fade in/out `NSImage` change in an `ImageView.` – Ruben Kazumov Sep 06 '21 at 06:04
  • @Sweeper I expect the `setValue` delivers the `NSValue? as Any?` from the model to the `MyImageView.image` by KVO. I did such a trick with an `NSTableColumn` subclass before, and everything was OK, but this time I stuck with the problem, that `MyImageView` do not call overridden `setValue.` – Ruben Kazumov Sep 06 '21 at 06:12
  • Which binding do you use? – Willeke Sep 06 '21 at 09:33
  • 1
    If you use the value binding then override the `objectValue` property. – Willeke Sep 06 '21 at 16:00
  • @Willeke, I love it! Thank you so much! I precisely looked for this property. Please, put this line in the answer, and I will accept it! – Ruben Kazumov Sep 06 '21 at 17:17

1 Answers1

1

The value binder calls the Objective-C method setObjectValue:. In Swift, override the objectValue property.

Willeke
  • 14,578
  • 4
  • 19
  • 47