我可以避免使用公共子类显式地转换对象吗?

时间:2010-04-05 16:07:25

标签: iphone objective-c cocoa-touch uiviewcontroller subclass

我有一个iPodLibraryGroup对象,而Artist和Album都继承了它。

当涉及到我的视图控制器时,虽然我发现我正在复制大量代码,例如我有一个ArtistListViewController和AlbumListViewController,即使它们都做了基本相同的事情。

我最终复制代码的原因是因为这些视图控制器都引用了Artist对象或al Album对象,我不知道如何设置它以便一个视图控制器可以同时处理这两个 - 这些视图控制器主要访问对象在iPodLibraryGroup中具有的共同方法。

作为一个例子,希望更清楚地考虑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;
}

这在ArtistListViewController中基本上完全重复了(以及更多重复代码的地狱),这样我就可以将局部变量强制转换为艺术家而不是专辑。

有没有办法不明确地在这里设置艺术家或专辑,以便相同的代码可以适用于任何iPodLibraryGroup的子对象?

2 个答案:

答案 0 :(得分:3)

重构您的代码,以便您拥有一个可在iPodLibraryGroup对象上运行的通用ListViewController,并拥有ArtistListViewController& AlbumListViewController都继承自它。

将所有常用部分推送到通用ListViewController,并让您的Artist / Album控制器仅实现/覆盖需要采取不同行为的方法。

答案 1 :(得分:0)

基于suggestion received on twitter我在iPodLibraryGroup上创建了一个协议,如下所示:

@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> {

…

}

然后在我的视图控制器中,我使用语法而不是声明指向声明的艺术家或专辑的指针:

id <iPodLibraryGroup> source;

我遇到的唯一问题是在调用NSObject方法时,我会收到编译器警告:

How to typecast an id to a concrete class dynamically at runtime?中讨论了这个问题,我在调用NSObject方法之前将我的“source”引用转换为(iPodLibraryGroup *)来解决它,例如:

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