Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
565 views
in Technique[技术] by (71.8m points)

macos - iTunes-like count buttons using Cocoa bindings

I want to display some items in my sidebar, with the count of each tag also displayed:

enter image description here

How do I do this efficiently and automatically? The easy option would be to use cocoa bindings, but I'm not sure what the best way to do this: would each button needs it's own NSArrayController with a fetch predicate set for the 'tag'? That could end up with X number of NSArrayControllers (one for each tag) which would be pretty heavy-weight (I would think).

The other option is to create fetch requests manually, then refetch for every change in managed object context. But that seems a bit messy and not-as-automatic.

Is there a simpler solution for this? I've googled around and haven't found anything.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Let's assume that in your NSOutlineView you have a childrenKeyPath of "children" and the children have a boolean isNew attribute. What you want is a nice numberOfNewItems bubble in the cell view for one object class. I'll call that the parent object.

If you just want the number of objects in the childrenKeyPath, heck, that's even easier, but I'll take you through the more complex case of tracking a specific boolean property on the children because it's easy enough to simplify this pattern.

In the table cell view for the parent object add a recessed button with the title bound to objectValue.numberOfNewItems and hidden bound to objectValue.NumberOfNewItems with value transformer NSNegateBoolean. If you just want the number of children, swith those keypaths to objectValue.children.count and you're done. If you want to track a property like isNew, let's continue...

In the parent object class, there is this code:

- (NSNumber*) numberOfNewItems
{
     // Collection operator on boolean returns total number of new children
     return [self valueForKeyPath:@"[email protected]"];
}

// This setter does nothing, but with KVO it causes bindings 
//  to numberOfNewItems to call the above getter
- (void) setNumberOfNewItems:(NSNumber*)number { }

//  This ensures that changes to the children set causes KVO calls to the above getter
+ (NSSet*) keyPathsForValuesAffectingNumberOfNewItems
{
    return [[NSSet alloc] initWithObjects:@"children", nil];
}

What that does is cause numberOfNewItems to be recalculated any time the table cell's objectValue gets a new child added to or removed from its children to-many relationship.

In the childItem class, there's this in the one place that the childItem is transitioned from isNew to not-New:

// If collapsing an item, mark it as not new
if (!isExpanded.boolValue && self.isNewValue) {
    self.isNew = @NO;
    [self.parent setNumberOfNewItems:nil]; // Triggers KVO for button binding
}

... and what that does is use the parent's empty setNumberOfNewItems setter to force the button binding to call the getter. So the whole to-many children relationship is enumerated each time an item is marked not-new. I supposed that could be improved, but I haven't played around with that yet.

I took advantage of the fact that an item is marked not-new only one place in my code. If you have several things resetting or setting isNew in the child, you might override setIsNew in the childItem class to call self.parent setNumberOfNewItems:nil instead.

The trick here is that having the parent add itself as a KVO observer for the isNew keypath for all children would be a terrible pain. So I wanted to avoid that. If you simply have the children call the empty setter in the parent, the parent can own the calculation, and there's no KVO outside what the bindings use.

Looks like this:

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...