get ready for thisnotified about this deal

Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.
I have an NSView subclass which is bound to the arrangedObjects of an NSArrayController. When the array has an item inserted or removed the view is notified. How do I get it to be notified if a model stored in the array has an attribute changed?
Do I need to add my view as an observer to every (relevant) attribute of every item added to the array?
When an item is added to or removed from the array I am notified via observeValueForKeyPath:ofObject:change:context: in my NSView subclass. I am not notified of changes to the models stored in the array but I could, every time I am notified of an insertion, add the view as an observer to the new item's attributes. Is this the best way to do this?
I overrode addObserver for the model class so that I could see what happens and noticed that NSTableView columns bound to the arrangedObjects add themselves as observers to the appropriate attributes. Can this be made to happen automagically or do I set up the observations manually?
32k1085111
A big thank you to dreamlax but I think I didn't do a good enough job explaining my problem. My model class was observable and produced the right notifications but I couldn't work out how to observe them without observing every item in the array directly.
I think the documentation for key paths could be improved because I couldn't find anything that explained the very simple change I needed to make. There's some good info the array magic keypaths but no simple "these are the common things" documentation.
Anyway. Previously in my NSView subclass I had the following:
- (void) bind:(NSString *)binding toObject:(id)observable withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
if ([binding isEqualToString:@"observedObjects"]) {
[observable addObserver:self forKeyPath:@"arrangedObjects" options:0 context:nil];
[super bind:binding toObject:observable withKeyPath:keyPath options:options];
To get notification of changes to the models within the NSArrayController's arrangedObjects all I needed to add was observation of arrangedObjects.name (for the name property of my model). So the above code became:
- (void) bind:(NSString *)binding toObject:(id)observable withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
if ([binding isEqualToString:@"observedObjects"]) {
[observable addObserver:self forKeyPath:@"arrangedObjects" options:0 context:nil];
[observable addObserver:self forKeyPath:@"arrangedObjects.name" options:0 context:nil];
[super bind:binding toObject:observable withKeyPath:keyPath options:options];
That's it! Now if any object in arrangedObjects gets its name changed I am notified.
Maybe rather than observing potentially many key value paths, why not have each object in the array post a notification when something has changed, then only one object needs to observe one notification instead of one object observing many key value paths.
Also, your arrayed objects could also respond to a class method called +keyPathsForValuesAffecting&key& where &key& is your key name. Here's an example: paymentDue is a key, which is affected when the values invoiceItems.count or paymentsMade have changed. When invoiceItems.count or paymentsMade has changed, anything bound to paymentDue is sent a notification.
+ (NSSet *) keyPathsForValuesAffectingPaymentDue:
return [NSSet setWithObjects:@"invoiceItems.count", @"paymentMade", nil];
If you are running on 10.4, or are targeting 10.4 or earlier, you'll need to use
method instead, but it essentially boils down to the same thing.
To clarif you can still have each object in the array manually call
[[NSNotificationCenter defaultCenter] postNotificationName:@"ModelDidChange" object:self];
Then, with some controller code you can register for notification updates from your objects. If you choose a unique notification name then you won't need to manually listen from specific objects, you can tell the NSNotificationCenter that you want to receive notifications from any object. Your controller can work out which object has changed quite easily.
Register with the notification center (these methods should be in a controller object):
// This string could really be just about anything you want, but make it conspicuous.
static NSString * const ModelDidChangeName = @"ModelDidChange";
- (void) awakeFromNib
// using nil for the object parameter will make the notification center
// invoke modelDidChange: regardless of who the sender is.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(modelDidChange:) name:ModelDidChangeName object:nil];
Implement a method to handle the notification.
- (void) modelDidChange:(NSNotification *) notification
MyModelClass *myObject = [notification object];
// do stuff with your model if necessary.
// do stuff with your view too
Get your model objects to post notifications when parts of them change:
@implementation MyModelClass
- (void) setSomething:(NSString *) newThing
[something autorelease];
something = [newThing copy];
if (something == nil)
// special case scenario for when something is nil
// do stuff, modify MyModelClass instance's attributes
[[NSNotificationCenter defaultCenter] postNotificationName:ModelDidChange object:self];
// the controller's modelDidChange: method is automatically invoked.
If your model is properly KVC compliant and made with the appropriate KVO callbacks, manual notifications won't be necessary.
52.4k15112158
Your Answer
Sign up or
Sign up using Google
Sign up using Facebook
Sign up using Stack Exchange
Post as a guest
Post as a guest
By posting your answer, you agree to the
Not the answer you're looking for?
Browse other questions tagged
Stack Overflow works best with JavaScript enabled

我要回帖

更多关于 how about this 的文章

 

随机推荐