7
votes

Let's say, for illustration, I was writing an iTunes clone app in Cocoa, that was backed by CoreData. For simplification's sake, let's say there are two "sections", "Library" with things like Music, Movies, Radio, etc. And a second section called "Playlists" which holds user-generated playlists (just dumb lists, not smart playlists).

So the SourceList itself would typically be implemented with NSOutlineView, that's generally straightforward.

The Library section of the source list doesn't really house anything generated by the user, only "features" of the app (in essence) where the Playlists section only holds custom lists as created by the user. How would one do this with Bindings and CoreData? Is it possible just to bind the Playlists section to the user's data and have a custom way of displaying the Library features?

I'm still getting my feet wet with Bindings and AppKit in general, so please bear with me. I appreciate the help. I should add, I'm targeting 10.6 and above.

2

2 Answers

6
votes

I haven't had a lot of experience with core data, but I have made extensive use of Cocoa's bindings. In my experience, something like this works best with an intermediate NSArray of objects which is "manually" adjusted.

As an example, I imagine you would have a custom NSArray of playlists that are user-generated, and you would also have a separate NSArray containing your standard Library items. With this setup, I would create a property in one of your controllers called combinedArray, which would be the property that gets bound to your NSOutlineView. I would then bind your user-generated playlist array to the controller, and have some code in the controller automatically update the combined array whenever the playlist array is modified.

Here is a quick mock-up:

TheController.h

@interface TheController : NSObject
{
    NSArray * combinedArray;
    NSArray * userPlaylists;
}
@property (retain) NSArray * combinedArray;
@property (copy) NSArray * userPlaylists;
@end

TheController.m

@implementation TheController

@synthesize combinedArray;
@synthesize userPlaylists;
- (void)setUserPlaylists:(NSArray *)newLists
{
    // standard property setting code:
    if (newLists != userPlaylists)
    {
        [userPlaylists release];
        userPlaylists = [newLists copy];
    }

    // modify the combined array:
    NSMutableArray * allItems = [NSMutableArray arrayWithCapacity:0];
    [allItems addObjectsFromArray:standardLibrary];
    [allItems addObjectsFromArray:userPlaylists];
    [self setCombinedArray:allItems];
}

@end
1
votes

Since the source list in this case is really a "scope" and not a flat list of nothing but instances of some "LibraryItem" entity, I think it's easier to implement this the "old fashioned" way (ie, table data source protocol).

This gives you precise control over grouping, how/when to mix "static" items (like "Library" and "Music", and "Movies", "Playlists") with items from your store (like the individual Playlist items under the "Playlists" section).

It's also a little easier to deal with drag and drop, in my opinion, which is key when preventing a Playlist item from being dropped upon your "Movies" group.