I have a Core Data model with two entities: Video
and Playlist
.
- A
Video
can be a member of manyPlaylist
s - A
Playlist
can have manyVideo
s, including the sameVideo
multiple times - A
Playlist
'sVideo
s are ordered
Video
<<----->>Playlist
That being said, I've decided that I need a third entity: Playlist Item
.
- A
Playlist Item
has an index - A
Playlist Item
can only have a relationship with oneVideo
entity and onePlaylist
entity
And so, this causes the original specification to be revised...
- A
Video
can have manyPlaylist Item
s - A
Playlist
can have manyPlaylist Item
s, but eachPlaylist Item
has a unique index - A
Playlist
'sPlaylist Item
s are ordered using the index attribute
Video <---->> Playlist Item <<----> Playlist
So, the addition of the Playlist Item
entity allows me to have many-to-many relationships between Video
and Playlist
and still maintain ordered lists. Adding this third entity however adds complexity to the overall design.
I am wondering if it is wise to hide that complexity managing the Playlist Item
objects in the Video
and Playlist
implementations.
Video
@interface Video : NSManagedObject
@property (strong, nonatomic) NSSet *playlists; // Custom accessor; Transient attribute; data persisted in Playlist Item
// No declared NSSet for playlistItems
@end
Playlist
@interface Playlist: NSManagedObject
@property (nonatomic, strong) NSArray *videos; // Custom accessor...
// No declared playlistItems here either!
@end
It seems by doing this I will gain code that is better at revealing intentions.
The code smell I'm getting is that NSManagedObjects
subclasses are model classes and should therefore not have any controller type glue. Furthermore it makes my Video
and Playlist
classes completely dependent upon the Playlist Item
s class. But, all of that said writing the accessor is trivial, which is why I'm considering this approach:
- (NSArray *)videos
{
[self willAccessValueForKey:@"videos"];
NSArray *v = [self primitiveVideos];
[self didAccessValueForKey:@"videos"];
if (v) {
return v;
}
NSSet *pi = [self playlistItems];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"index" ascending:YES];
NSArray *orderedPlaylistItems = [pi sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
NSUInteger count = [orderedPlaylistItems count];
NSMutableArray *videos = [NSMutableArray arrayWithCapacity:count];
for (int index = 0; index < count; index++) {
[videos addObject:[[orderedPlaylistItems objectAtIndex:index] video]];
}
v = videos;
[self setPrimitiveVideos:v];
return v;
}
(This code is pretty rough, but you get the point, a few lines and voila! an array of video objects from the set of playlist items)
Maybe there is a design pattern or best practice that would help guide my decision?
1 Answer 1
Perhaps I'm missing something, but it seems that the Video
objects don't really need to know about what playlists they belong to, do they?
A playlist is a collection of videos. You don't need a playlist index object. You just need an array on each playlist that keeps track of what videos are on its playlist and in what order. A simple array does all this for you.
It seems to me that the only reason a video would need to know what playlists it belonged to is if you wanted to provide some functionality for a video to quickly find all playlists it belonged to. And when I say this, I mean a request where it's important for this information to be returned near instantly.
Even without the video knowing any information about the playlists, your code could still iterate through every playlist asking it whether or not it contained a given video and get the answer to what all playlists the video belongs to. This might be a little time consuming, but I think it's a rare request.
But it seems what's most likely is that a user will either want to play an individual video, or play a playlist. The request to play all playlists that contain this particular video seems an odd one to me.
-
\$\begingroup\$ You are correct, however the Core Data framework forces my hand a bit - to-many relationships are represented as
NSSet
s notNSArrays
. That's really the crux of the problem. The backward relationship (from video to playlist) is a consequence of how Core Data models relationships and maintains referential integrity. \$\endgroup\$edelaney05– edelaney052014年07月06日 15:16:40 +00:00Commented Jul 6, 2014 at 15:16 -
\$\begingroup\$ Oh, now I understand. Let me think about this bit and see if I can come up with a better solution. \$\endgroup\$nhgrif– nhgrif2014年07月06日 15:17:49 +00:00Commented Jul 6, 2014 at 15:17