views:

92

answers:

2

I have an iPodLibraryGroup object and Artist and Album both inherit from it.

When it comes to my view controllers though I find that I'm duplicating lots of code, for example I have an ArtistListViewController and and AlbumListViewController even though they're both doing basically the same thing.

The reason I've ended up duplicating the code is because these view controllers each refer to either an Artist object or al Album object and I'm not sure how to set it up so that one view controller could handle both — these view controllers are mainly accessing methods that that the objects have in common from iPodLibraryGroup.

As an example, to hopefully make this clearer consider this code in AlbumListViewController:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    Album *album = nil; 
    album = [self albumForRowAtIndexPath:indexPath inTableView:tableView];

    …

    if (!album.thumbnail)
    {
        [self startThumbnailDownload:album forIndexPath:indexPath inTableView:tableView];
        cell.imageView.image = [UIImage imageNamed:@"Placeholder.png"];                
    }
    else
    {
       cell.imageView.image = album.thumbnail;
    }


    return cell;
}

This is essentially completely repeated (along with a hell of a lot more repeated code) in ArtistListViewController just so that I can typecast the local variable as an Artist instead of an Album.

Is there a way to not explicitly need to set Artist or Album here so that the same code could work for any object that is a child of iPodLibraryGroup?

+3  A: 

Refactor your code so you have a generic ListViewController that operates on iPodLibraryGroup objects, and have ArtistListViewController & AlbumListViewController both inherit from it.

Push all the common parts up to the generic ListViewController, and have your Artist/Album controllers only implement/override the methods that need to behave differently.

David Gelhar
this would work too I imagine but the protocol solution I marked as the answer was a much quicker implementation.
prendio2
A: 

Based on a suggestion received on twitter I created a protocol on iPodLibraryGroup as follows:

@protocol iPodLibraryGroup <NSObject>
@required

@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain, readonly) NSString *sort_name;

…

- (void)downloadImageFromURL:(NSURL *)image_url;
- (void)cancelImageDownload;
- (void)downloadImageCannotStart;

@end


@interface iPodLibraryGroup : NSObject <iPodLibraryGroup> {

…

}

Then within my view controllers, instead of declaring pointers to declared Artists or Albums I use the syntax:

id <iPodLibraryGroup> source;

The only issue I encountered was when calling NSObject methods, I would get a compiler warning:

This issue is discussed in http://stackoverflow.com/questions/899068/how-to-typecast-an-id-to-a-concrete-class-dynamically-at-runtime and I resolved it by casting my "source" reference as an (iPodLibraryGroup *) before calling NSObject methods, for example:

[(iPodLibraryGroup *)source addObserver:self forKeyPath:@"pendingResponseForDetailedInfo" options:0 context:nil];
prendio2