viewDidLoad and KVO
I often have a view controller that displays a view associated with a model object. So, I'll have a foo property on that VC, and in the prepareForSegue call that presents the VC, I'll setFoo on it. In my -setFoo: method, I set up KVO on the properties of the foo that I'm interested in displaying. In the -observe... method, I update the various bits of UI as properties change. This generally works very well, except when I get to the VC via a segue. -prepareForSegue gets called before -viewDidLoad, so none of the IBOutlets exist yet. I can solve this by doing an explicit UI update step in -viewDidLoad, but that ends up effectively duplicating the UI update code. I can load the view in -setFoo: by referencing self.view, but this seems like a hack. What are other people doing to address this? Any best practice you guys like? -- Rick ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: viewDidLoad and KVO
In my -setFoo: method, I set up KVO on the properties of the foo that I'm interested in displaying. In the -observe... method, I update the various bits of UI as properties change. If you're doing something like this: - (void)setFoo: (Foo *)aFoo { [foo removeObserver:self forKeyPath:@whatever...]; foo = aFoo; [foo addObserver:self forKeyPath:@whatever...; } we used that pattern for a while but were constantly getting bit by observers on objects being dealloced or KVO firing and triggering unwanted side effects if we called setFoo: in dealloc. So we did a complete switch over to doing [self addObserver:self forKeyPath:@foo.whatever... in init, and removeObserver in dealloc, because you can remove an observer on yourself in dealloc without the observers still registered warning. Since it's on self, you can set it before foo exists, and setFoo: triggers it. Plus we could use synthesized setters. - Original Message - From: Rick Mann rm...@latencyzero.com To: Cocoa Developers cocoa-dev@lists.apple.com Sent: Wednesday, June 4, 2014 10:03:20 PM Subject: viewDidLoad and KVO I often have a view controller that displays a view associated with a model object. So, I'll have a foo property on that VC, and in the prepareForSegue call that presents the VC, I'll setFoo on it. In my -setFoo: method, I set up KVO on the properties of the foo that I'm interested in displaying. In the -observe... method, I update the various bits of UI as properties change. This generally works very well, except when I get to the VC via a segue. -prepareForSegue gets called before -viewDidLoad, so none of the IBOutlets exist yet. I can solve this by doing an explicit UI update step in -viewDidLoad, but that ends up effectively duplicating the UI update code. I can load the view in -setFoo: by referencing self.view, but this seems like a hack. What are other people doing to address this? Any best practice you guys like? -- Rick ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://urldefense.proofpoint.com/v1/url?u=https://lists.apple.com/mailman/options/cocoa-dev/lrucker%2540vmware.comk=oIvRg1%2BdGAgOoM1BIlLLqw%3D%3D%0Ar=yJFJhaNnTZDfFSSz1U9TSNMmxGyib3KjZGuKfIhHLxA%3D%0Am=qYOnOaiiYwn8zuydsyBcZuhg6AnT0QTIlKRcBpdwfnM%3D%0As=a80229e6e590ffa9a96606cdc929d245804adff0b0a29bb275a85110c02b83bb This email sent to lruc...@vmware.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: viewDidLoad and KVO
On Jun 5, 2014, at 00:26 , Lee Ann Rucker lruc...@vmware.com wrote: If you're doing something like this: - (void)setFoo: (Foo *)aFoo { [foo removeObserver:self forKeyPath:@whatever...]; foo = aFoo; [foo addObserver:self forKeyPath:@whatever...; } we used that pattern for a while but were constantly getting bit by observers on objects being dealloced or KVO firing and triggering unwanted side effects if we called setFoo: in dealloc. So we did a complete switch over to doing [self addObserver:self forKeyPath:@foo.whatever... in init, and removeObserver in dealloc, because you can remove an observer on yourself in dealloc without the observers still registered warning. Since it's on self, you can set it before foo exists, and setFoo: triggers it. Plus we could use synthesized setters. I collect the removeObserver calls into an ignoreFoo method, and similarly the addObserver in an observeFoo method. Then in -dealloc I call -ignoreFoo. I've never run into the (annoying) registration mismatch errors. Your suggestion is a good one, but I don't think it solves the problem I have of -setFoo: being called before -viewDidLoad (before the IBOutlets are non-nil). -- Rick ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: viewDidLoad and KVO
Why don't you use viewWillAppear and viewDidDisappear, to register and unregister observers to your foo property object? If you don't use ARC, be carefull to unregister on dealloc too! El 05/06/2014, a las 09:30, Rick Mann rm...@latencyzero.com escribió: On Jun 5, 2014, at 00:26 , Lee Ann Rucker lruc...@vmware.com wrote: If you're doing something like this: - (void)setFoo: (Foo *)aFoo { [foo removeObserver:self forKeyPath:@whatever...]; foo = aFoo; [foo addObserver:self forKeyPath:@whatever...; } we used that pattern for a while but were constantly getting bit by observers on objects being dealloced or KVO firing and triggering unwanted side effects if we called setFoo: in dealloc. So we did a complete switch over to doing [self addObserver:self forKeyPath:@foo.whatever... in init, and removeObserver in dealloc, because you can remove an observer on yourself in dealloc without the observers still registered warning. Since it's on self, you can set it before foo exists, and setFoo: triggers it. Plus we could use synthesized setters. I collect the removeObserver calls into an ignoreFoo method, and similarly the addObserver in an observeFoo method. Then in -dealloc I call -ignoreFoo. I've never run into the (annoying) registration mismatch errors. Your suggestion is a good one, but I don't think it solves the problem I have of -setFoo: being called before -viewDidLoad (before the IBOutlets are non-nil). -- Rick ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/alejandro.visiedo%40gmail.com This email sent to alejandro.visi...@gmail.com ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: viewDidLoad and KVO
On 5 Jun 2014, at 3:03 pm, Rick Mann rm...@latencyzero.com wrote: I can solve this by doing an explicit UI update step in -viewDidLoad, but that ends up effectively duplicating the UI update code. I can load the view in -setFoo: by referencing self.view, but this seems like a hack. What are other people doing to address this? Any best practice you guys like? I guess this is really a question about the timing of the -setFoo: call relative to the -loadView call, and that would probably imply that calling -setFoo: is actually the responsibility of a higher-level controller than this one (probably the object that alloc/inits the view controller). So maybe you could set up a simple informal delegate method such that the VC has the higher-level controller as its delegate, and when -viewDidLoad: is called, it asks the delegate to provide 'foo' at that time. As far as observing 'foo' via KVO, the way I generally like to do this is to have my VC implement methods that have the exact same form (as setters) as the properties they're interested in on the model object, then my observer method boils down to a very simple trampoline: - (void) observeValueForKeyPath: { [self setValue:[changeDict objectForKey:NSKeyValueChangeNewKey] forKey:keyPath]; } This leverages the automatic unwrapping of property values that KVC already does, so I don't have to do it again myself. This is so general I have it wrapped up into a simple base class that all of these similar view controllers subclass - each subclass then just adds the setKey : methods it needs. For setting up and tearing down the KVO, I do as you do, but something that can simplify this is to get the observed objects to vend a list of observable properties that the observer can simply iterate over and add itself as an observer for each one. This is typically a class method. The downside would be that there may well be properties of no interest, but this approach implies you still need a cover method for those properties, but of course you can also override -setValue:forUndefinedKey: not to throw an exception but to ignore instead. Otherwise, just observing the properties of interest one by one is also fine. I have found though that by generalising the approach, if you have a large number of similar but variant interfaces on a large number of similar but variant model objects, it can generalise away a lot of the tedium. I've actually found this approach a lot easier to live with than bindings, which also claim to generalise the problem (as well as moving it into IB), but can be opaque as a result. In terms of setting up the initial state of the UI, provided -setFoo: is called at the right time (after the view is loaded), then passing the NSKeyValueObservingOptionInitial as a flag to the -addObserver: call ensures that the same trampolining method is used both for initial setup and ongoing changes to the model property. As for tear-down at dealloc time, -setFoo:nil is fine, as it then tears down the observation on the existing (retained) foo object prior to releasing it. I've not run into issues with the unregistering observations error, at least not since this was improved a lot a few OS versions back. --Graham ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: viewDidLoad and KVO
On Jun 5, 2014, at 06:26 , Alejandro Visiedo García alejandro.visi...@gmail.com wrote: Why don't you use viewWillAppear and viewDidDisappear, to register and unregister observers to your foo property object? If you don't use ARC, be carefull to unregister on dealloc too! That, combined with observing on self.foo, might work, except that the appear/disappear calls aren't guaranteed to be balanced. El 05/06/2014, a las 09:30, Rick Mann rm...@latencyzero.com escribió: On Jun 5, 2014, at 00:26 , Lee Ann Rucker lruc...@vmware.com wrote: If you're doing something like this: - (void)setFoo: (Foo *)aFoo { [foo removeObserver:self forKeyPath:@whatever...]; foo = aFoo; [foo addObserver:self forKeyPath:@whatever...; } we used that pattern for a while but were constantly getting bit by observers on objects being dealloced or KVO firing and triggering unwanted side effects if we called setFoo: in dealloc. So we did a complete switch over to doing [self addObserver:self forKeyPath:@foo.whatever... in init, and removeObserver in dealloc, because you can remove an observer on yourself in dealloc without the observers still registered warning. Since it's on self, you can set it before foo exists, and setFoo: triggers it. Plus we could use synthesized setters. I collect the removeObserver calls into an ignoreFoo method, and similarly the addObserver in an observeFoo method. Then in -dealloc I call -ignoreFoo. I've never run into the (annoying) registration mismatch errors. Your suggestion is a good one, but I don't think it solves the problem I have of -setFoo: being called before -viewDidLoad (before the IBOutlets are non-nil). -- Rick ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/alejandro.visiedo%40gmail.com This email sent to alejandro.visi...@gmail.com -- Rick ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com