genaks
genaks

Reputation: 757

Detect UILabel text change in swift

Is there a way to get notified when there is a change in a UILabel's text or would I be better off using a UITextField with userInteractionEnabled set to false and using its UIControlEditingChanged event to fulfil my purpose?

For ex. I need to run certain lines of code every time I change the UILabel's text and accordingly. So instead of writing those 100 lines of almost similar code for every case I change the UILabel's text, I wish to write it together in one place and call it every time the UILabel is changed. I don't even know if that makes any sense. Forgive me but I cannot expose much of the code.

Upvotes: 22

Views: 17973

Answers (5)

zramled
zramled

Reputation: 331

Swift 5

If you want to observe text changes in the label and make an animation. You need to create subclass UILabel

class ObservedLabelAnimate: SpringLabel {

    override var text: String? {
        didSet {
            if let text = text {
                if oldValue != text {
                    animation = "fadeInLeft"
                    duration = 1.2
                    animate()
                }
                print("This is oldvalue \(oldValue), and this is the new one \(text)")
            }
        }
    }
}

for this example, I subclass 'SpringLabel' that inherits from UILabel

from https://github.com/MengTo/Spring

Basically it will check if the oldValue and text (new one) is different then the animation will be fired

To use:

@IBOutlet weak var label: ObservedLabelAnimate!

Upvotes: 1

Paul King
Paul King

Reputation: 2001

For Swift 3.2 and later, the preferred method is to use a closure-based observer:

@IBOutlet public weak var label: UILabel!

var textObserver: NSKeyValueObservation?

func someAppropriateFunction() {
  ...
  textObserver = label.observe(\.text) { [weak self] (label, observedChange) in
    self?.updateStuff()
  }
}

The closure will pass you the label instance and an NSKeyValueObservedChange that includes the following properties:

  indexes: IndexSet?
  isPrior: Bool
  kind: NSKeyValueObservedChange<Value>.Kind
  newValue: Value?
  oldValue: Value?

Upvotes: 5

atreat
atreat

Reputation: 4413

You can do this simply with a subclass of UILabel:

class Label : UILabel {
    override var text: String? {
        didSet {
            print("Text changed from \(oldValue) to \(text)")
        }
    }
}

oldValue is a special value provided by Swift. See Property Observers

Upvotes: 4

devxoul
devxoul

Reputation: 2228

Swift 3

First, add an observer to UILabel for key path text.

label.addObserver(self, forKeyPath: "text", options: [.old, .new], context: nil)

Then

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
  if keyPath == "text" {
    print("old:", change?[.oldKey])
    print("new:", change?[.newKey])
  }
}

Swift 2

label.addObserver(self, forKeyPath: "text", options: [.Old, .New], context: nil)

Then

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if keyPath == "text" {
        print("old:", change["old"])
        print("new:", change["new"])
    }
}

Console Output

For example console would be:

old: Optional(<null>)
new: Optional(ABC)

Upvotes: 31

ridvankucuk
ridvankucuk

Reputation: 2407

Create a class that inherits from UILabel. Such as:

class YourLabel: UILabel {

    override var text: String? {
        didSet {
            if let text = text {
                println("Text changed.")
            } else {
                println("Text not changed.")
            }
        }
    }
}

Create a outlet of this class for your object.

@IBOutlet weak var label: YourLabel!
label.text = "abc"

Upvotes: 34

Related Questions