iOS 9: KVO no longer working
If you do a search for UIKit and KVO Compliance you will see that everyone says you can't rely on it. See this question and this question.
I don't know what changed, but I think you should just subclass UITextView and overload setContentSize: if you want to know when it changes.
is KVO still broken?
When Mike Ash says KVO is broken, he isn't talking about if it works or not. Ash is saying that the API is designed badly and this bad design limits what developers can do with it.
A better use of "KVO-esque" programming can be found in libraries like ReactiveCocoa.
If you want to learn more check out these links.
- https://leanpub.com/iosfrp/
- https://github.com/ReactiveCocoa/ReactiveCocoa
- https://github.com/ReactiveX/RxSwift
KVO not working (observing another class's property)
You written the observer in dealloc
method. There will be an issue, your object is being released when you are adding an observer, so there will be a crash when the KVO value is changed.
There is no crash and nothing is working, I think the reason is; the dealloc
method is never called. It means your view controller is never released (potentially a leak, a strong retain cycle is there).
Instead of that add that in your viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
ResultDataClass *resultData = [ResultDataClass getInstance];
[resultData addObserver:self forKeyPath:@"xxx" options:NSKeyValueObservingOptionNew context:NULL];
}
KVO not working for custom property of NSManagedObject
Adding as an answer since it became a learning exercise. Hopefully someone else too would be benefitted.
The app uses a multiple managedObjectContext(moc) architecture. 1 private moc to make changes and 1 main thread moc that synchronises itself using mergeChanges.
In above code, navigationItem
is using the folder instance kept with main-moc. The DynamicProperty is listening to KVO changes on this main-moc's folder instance. Let's call this main-folder. When I make changes, I modify the folder instance we have on private-moc. Let's call it private-folder.
On modifying private-folder and calling save
on private-moc, a notification of name NSManagedObjectContextDidSave
is broadcasted. main-moc synchronizes itself using mergeChanges.
mergeChanges changes main-folder, but notice that it would never call the computed-property-setter availability
. It directly changes internalAvailability
.
And thus, no KVO notifications are posted of our computed property.
TL;DR When doing KVO on a NSManagedObject subclass, use a stored property instead of computed one. In case you have a multi-moc (managed object context) scenario and use mergeChanges to synchronise, setter for your computed property is not called when synchronising.
Edit (Solution): add method of the pattern keyPathsForValuesAffecting<KeyName>
KVO relevant documentation
@objc class func keyPathsForValuesAffectingAvailability() -> Set<NSObject> {
return [#keyPath(Folder.internalAvailability) as NSObject]
}
KVO keyPathsForValuesAffecting doesn't work
You need to use @objc
on your keyPathsForValuesAffecting
method so that the KVO machinery can find it using the Objective-C runtime:
@objc class func keyPathsForValuesAffectingFullName() -> Set<NSObject> {
return ["name, "surname"]
}
By the way, you can use a property instead, and you can use the #keyPath
special form to make the compiler help you catch errors:
@objc class var keyPathsForValuesAffectingFullName: Set<String> {
return [#keyPath(name), #keyPath(surname)]
}
You should also use dynamic
on the upstream properties (name
and surname
), as Ken Thomases advised.
Here's a full test program (as a macOS command-line program):
import Foundation
class DependencyTest: NSObject {
@objc dynamic var fullName: String {
return name + " " + surname
}
@objc dynamic var name = ""
@objc dynamic var surname = ""
@objc class var keyPathsForValuesAffectingFullName: Set<String> {
return [#keyPath(name), #keyPath(surname)]
}
}
class Observer: NSObject {
@objc let dep: DependencyTest
init(dep: DependencyTest) {
self.dep = dep
super.init()
addObserver(self, forKeyPath: #keyPath(Observer.dep.fullName), options: .prior, context: nil)
}
deinit {
removeObserver(self, forKeyPath: #keyPath(Observer.dep.fullName), context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("kvo: \(keyPath!) \(change?[.notificationIsPriorKey] as? Bool ?? false ? "prior" : "post")")
}
}
let d = DependencyTest()
let o = Observer(dep: d)
d.name = "Robert"
Output:
kvo: dep.fullName prior
kvo: dep.fullName post
Program ended with exit code: 0
KVO not working for `UIView.bounds` keypath when view resizing happens due to `autoresizingmask`
My issue was solved by observing \.layer.bounds
instead of \UIView.bounds
because I learned that the layer is the “source of truth” for a view’s layout, so I suspected the autoresizing mask was directly modifying the layer bounds without going through UIView.bounds
Related Topics
iOS 11 Animated Gif Display in Uiimageview
Swift Unsafemutablepointer<Unmanaged<Cfstring>> Allocation and Print
Uilabel, Uifont and Utf-8 Triangle
Xcode /Podfile.Lock: No Such File
Googleutilities/Appdelegateswizzler/Private/Gulapplication.H' File > Not Found
Disable Autorotate on a Single Subview in iOS8
Displaying Text One Character at a Time in Swift 2.0
Binding Viewmodel and Textfields with Swiftui
Re-Assigning Instance of Avaudioplayer in iOS13 Leads to Bad_Access Runtime Error
Delphi/Firemonkey Change iOS Screen Rotation at Runtime
Two Buttons Inside Hstack Taking Action of Each Other
Swiftui Foreach Index Out of Range Error When Removing Row
Capture Location in All States App
iOS 13 Set Uisearchtextfield Placeholder Color
How We Can Set the Light Content Style of Status Bar in iOS 9 for Whole Application
Download PDF and Save to the "Files" in Iphone, Not to the App Data, Swift