4

I want to implement a didSet over a "sub-attribute" of a variable.

Example:

@IBOutlet weak var myLabel: UILabel!
var myLabel.hidden { didSet{ "DO SOMETHING" } }

I want to hide/show some other views when myLabel.hidden attribute change. How can I do it?

Daniel Gomez Rico
  • 15,026
  • 20
  • 92
  • 162

3 Answers3

6

You can make a property like this

    var hideLabel: Bool = false {
    didSet {
        myLabel.isHidden = hideLabel
        //SHOW OR HIDE OTHER VIEWS
    }
}

By doing this you don't have to use KVO at the same time you can add more controls to hide to show at didSet context. I Believe this is a simpler way to do such a thing.

Amjad Husseini
  • 475
  • 7
  • 12
2

The standard process is to use KVO. Add observer when the view is loaded:

override func viewDidLoad() {
    super.viewDidLoad()

    label.addObserver(self, forKeyPath: "hidden", options: .New | .Old, context: nil)
}

When the view controller is deallocated, make sure to remove the observer.

deinit {
    label.removeObserver(self, forKeyPath: "hidden")
}

And do whatever you want inside the observeValueForKeyPath method:

override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
    NSLog("\(change)")

    // do whatever you want here
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • I get an exception in the `deinit`, my `label` is `nil`! I have my `UIViewController` inside a Tab controller – Daniel Gomez Rico Mar 04 '15 at 21:39
  • 1
    Yep, w tab bar controller you might instantiate view controller, but never load the view. So you'd check to see if it's `nil` or not before trying to call `removeObserver`. – Rob Mar 04 '15 at 21:58
1

Property observers can only be added to a class, not an instance. In order to do this you need to subclass UILabel and then override hidden's property observers.

EDIT: If you want to set custom observers on instances of CustomLabel, you can do this easily by adding block function variables to your CustomLabel that trigger on didSet or willSet

class CustomLabel: UILabel {

    var onDidSetHidden: ((Bool) -> ())?
    var onWillSetHidden: ((Bool) -> ())?

    override var hidden: Bool {
        didSet {
            if let block = onDidSetHidden {
                block(self.hidden)
            }
        }

        willSet (willBeHidden) {
            if let block = onWillSetHidden {
                block(willBeHidden)
            }
        }
    }
}

var custom = CustomLabel()
custom.onDidSetHidden = { (isHidden) in
    if isHidden {
        println("IS HIDDEN")
    } else {
        println("IS NOT HIDDEN")
    }
}

custom.hidden = true //prints 'IS HIDDEN'
kellanburket
  • 12,250
  • 3
  • 46
  • 73