observing contentSize (CGSize) with KVO in swift
With Swift 4, you can cast the result of the change
dictionary for the key NSKeyValueChangeKey.newKey
as being of type CGSize
:
if let size = change?[NSKeyValueChangeKey.newKey] as? CGSize {
/* ... */
}
The following UIViewController
implementation shows how to set a KVO stack in order to observe the changes of the contentSize
property of any UIScrollView
subclass (e.g UITextView
):
import UIKit
private var myContext = 0
class ViewController: UIViewController {
@IBOutlet weak var textView: UITextView!
/* ... */
override func viewDidLoad() {
super.viewDidLoad()
textView.addObserver(self, forKeyPath: #keyPath(UITextView.contentSize), options: [NSKeyValueObservingOptions.new], context: &myContext)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &myContext,
keyPath == #keyPath(UITextView.contentSize),
let contentSize = change?[NSKeyValueChangeKey.newKey] as? CGSize {
print("contentSize:", contentSize)
}
}
deinit {
textView.removeObserver(self, forKeyPath: #keyPath(UITextView.contentSize))
}
}
Note that with Swift 4, as an alternative to addObserver(_:, forKeyPath:, options:, context:)
and observeValue(forKeyPath:, of:, change:, context:)
, you can use observe(_:, options:, changeHandler:)
in order to track your UIScrollView
subclass contentSize
property changes:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var textView: UITextView!
var observer: NSKeyValueObservation?
/* ... */
override func viewDidLoad() {
super.viewDidLoad()
let handler = { (textView: UITextView, change: NSKeyValueObservedChange<CGSize>) in
if let contentSize = change.newValue {
print("contentSize:", contentSize)
}
}
observer = textView.observe(\UITextView.contentSize, options: [NSKeyValueObservingOptions.new], changeHandler: handler)
}
}
Are you on iOS? Because I am, I did the same thing and arrived at the same question; why NSSize
? Maybe that's just the xcode terminal playing a trick on us.
Anyway, you can cast it to an NSValue
then you will be able to use CGSizeValue
:
if let zeChange = change as? [NSString: NSValue] {
let oldSize = zeChange[NSKeyValueChangeOldKey]?.CGSizeValue()
let newSize = zeChange[NSKeyValueChangeNewKey]?.CGSizeValue()
}