Ответ 1
Ты сказал:
Но, думая об этом, я не думаю, что это будет работать на примитивы быстрых объектов, таких как
Int
, которые (я предполагаю) не наследуются отNSObject
и в отличие от версии Objective-C не будут помещаться вNSNumber
, если он помещен в словарь изменений.
Собственно, если вы посмотрите на эти значения, если наблюдаемое свойство равно Int
, оно приходит через словарь как NSNumber
.
Итак, вы можете остаться в мире NSObject
:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let newValue = change?[.newKey] as? NSObject {
if let oldValue = change?[.oldKey] as? NSObject {
if !newValue.isEqual(oldValue as Any) {
edit()
}
}
}
}
Или используйте их как NSNumber
:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let newValue = change?[.newKey] as? NSNumber {
if let oldValue = change?[.oldKey] as? NSNumber {
if newValue.intValue != oldValue.intValue {
edit()
}
}
}
}
Или, если бы это было значением Int
для некоторого свойства dynamic
некоторого класса Swift, я бы пошел дальше и произнес его как Int
:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let newValue = change?[.newKey] as? Int {
if let oldValue = change?[.oldKey] as? Int {
if newValue != oldValue {
edit()
}
}
}
}
Или, более кратко:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let newValue = change?[.newKey] as? Int, let oldValue = change?[.oldKey] as? Int, newValue != oldValue {
edit()
}
}
Вы спросили:
Также, вопрос бонуса, как я могу использовать переменную
of object
? Это не позволит мне изменить имя и, конечно, не любит переменные с пробелами в них.
of
- это внешняя метка для этого параметра (используется, если вы вызываете этот метод, в этом случае ОС вызывает это для нас, поэтому мы не используем эту внешнюю метку, не указанную в сигнатуре метода). object
является внутренней меткой (используется внутри самого метода). У Swift была возможность для внешних и внутренних меток для параметров на некоторое время, но она была действительно включена в API по сравнению с Swift 3.
В терминах использования этого параметра change
вы используете его, если вы наблюдаете свойства более чем одного объекта, и если эти объекты нуждаются в различной обработке на KVO, например:
foo.addObserver(self, forKeyPath: "bar", options: [.new, .old], context: &observerContext)
baz.addObserver(self, forKeyPath: "qux", options: [.new, .old], context: &observerContext)
И затем:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard context == &observerContext else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return
}
if (object as? Foo) == foo {
// handle `foo` related notifications here
}
if (object as? Baz) == baz {
// handle `baz` related notifications here
}
}
В стороне, я обычно рекомендую использовать context
, например, иметь private var
:
private var observerContext = 0
Затем добавьте наблюдателя в этот контекст:
foo.addObserver(self, forKeyPath: "bar", options: [.new, .old], context: &observerContext)
И пусть мой observeValue
убедитесь, что это его context
, а не один, установленный его суперклассом:
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard context == &observerContext else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return
}
if let newValue = change?[.newKey] as? Int, let oldValue = change?[.oldKey] as? Int, newValue != oldValue {
edit()
}
}