will/didChangeValueForKey: Real World Usage
will/didChangeValueForKey: Real World Usage
- Subject: will/didChangeValueForKey: Real World Usage
- From: Jerry Krinock <email@hidden>
- Date: Mon, 22 Oct 2007 13:02:26 -0700
In custom classes, I often run into a situation of wanting to expose
a binding to an ivar which is dependent on internal variables.
For example, I have a custom view (a "tag cloud") with many button-
like regions, each of which can be "selected" or not. Each has an
index in an array, and I keep track of which are selected using an
NSMutableIndexSet. NSMutableIndexSet has many handy methods to
mutate the set, easily handling multiple selection, deselection,
"extending" the selection, etc. and it all works very nicely.
In order to do something useful with the selection, I implemented a
getter [1] which returns an array containing the 'text' ivars of each
selected object. To simplify external code, however, I would like to
be able to make read-only bindings to this getter, but in order for
this to work I had to go through my view class and surround every
time I touch that NSMutableIndex set with pairs of -
willChangeValueForKey: and -didChangeValueForKey:.
It works fine, but there are two things that bother me about this:
1. I had to add -will/did pairs change in ^six^ places in my view
class. If I forget to add these in future revisions, bugs may be
introduced. Also, 12 lines of code to say something simple like
"tell observers whenever this mutable index set changes" seems like
alot of work for something (bindings) which is supposed to "reduce
the code you have to write". Is there an easier way to do this? Or
maybe it is more accurate to say that bindings does not really reduce
the amount of code in the world, but it moves code from models into
views, and since views are ^usually^ provided by others, it reduces
the code that "you" have to write.
2. I have heard the warnings against calling -will/
didChangeValueForKey without "really" changing anything in between.
Well, consider what happens when the user clicks in an empty part of
the view with no modifier keys:
[self willChangeValueForKey:@"selectedTags"] ;
[[self selectedIndexSet] removeAllIndexes] ;
[self didChangeValueForKey:@"selectedTags"] ;
Now, what if the user clicks there a second time? The second -
removeAllIndexes will actually have no effect on selectedTags. Am I
disobeying the rule and possibly setting myself up for a crash in
some future OS version?
Thanks,
Jerry Krinock
P.S. My "tag cloud" view is built on the one recently posted by
Robert Pointon [2], which is ^very^ cool. I'll make my final version
available after I get these concerns resolved.
[1]...
- (BOOL)isSelectedBoxedTag:(BoxedTag*)boxedTag {
BOOL isSelected = NO ;
int index = [_boxedTags indexOfObject:boxedTag] ;
if (index != NSNotFound) {
isSelected = [[self selectedIndexSet] containsIndex:index] ;
}
return isSelected ;
}
- (NSArray*)selectedTags {
NSEnumerator* e = [_boxedTags objectEnumerator] ;
NSMutableArray* selectedTags = [[NSMutableArray alloc] init] ;
BoxedTag* boxedTag ;
while ((boxedTag = [e nextObject])) {
if ([self isSelectedBoxedTag:boxedTag]) {
[selectedTags addObject:[boxedTag text]] ;
}
}
NSArray* output = [selectedTags copy] ;
[selectedTags release] ;
return output ;
}
[2] http://www.fernlightning.com/doku.php?id=randd:tcloud:start
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden