你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> UITableView“優雅”支持不同類型的Cell

UITableView“優雅”支持不同類型的Cell

編輯:IOS開發基礎

在某些業務場景下,同一個UITableView需要支持多種UITableViewCell。考慮一下即時通信的聊天對話列表,不同的消息類型對應於不同的UITableViewCell,同一個tableview往往需要支持多達10種以上的cell類型,例如文本、圖片、位置、紅包等等。一般情況下,UITableViewCell往往會和業務數據模型綁定,來展示數據。根據不同的業務數據,對應不同的cell。本文將探討如何有效的管理和加載多種類型的cell。

為了方便討論,假設我們要實現一個員工管理系統。一個員工包含名字和頭像。如果員工只有名字,則只展示名字,如果只有頭像,則只展示頭像,如果既有名字,又有頭像,則需要既展示頭像又展示名字。

我們用一個Person類表示員工,用三種不同的cell來處理不同的展示情況。

@interface Person : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) NSString *avatar;

@end
/*負責展示只有名字的員工*/

@interface TextCell : BaseCell

- (void)setPerson:(Person *)p;

@end
/*負責展示只有頭像的員工*/

@interface ImageCell : BaseCell

- (void)setPerson:(Person *)p;

@end
/*負責展示只有既有名字又有頭像的員工*/

@interface TextImageCell : BaseCell

- (void)setPerson:(Person *)p;

@end

這三個類都繼承了BaseCell,BaseCell繼承UITableViewCell

@interface BaseCell : UITableViewCell

- (void)setPerson:(Person *)p;

@end

下面我們在UITableView的delegate來處理展示Cell

第一次嘗試:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    BaseCell *cell;
    NSString *cellIdentifier;

    switch (p.showtype) {
        case PersonShowText:
            cellIdentifier = @"TextCell";
            break;
        case PersonShowAvatar:
            cellIdentifier = @"PersonShowAvatar";
            break;
        case PersonShowTextAndAvatar:
            cellIdentifier = @"PersonShowTextAndAvatar";
            break;
        default:
            break;
    }

    cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

    if (!cell) {
        switch (p.showtype) {
            case PersonShowText:
                cell = [[TextCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
                break;
            case PersonShowAvatar:
                cell = [[ImageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
                break;
            case PersonShowTextAndAvatar:
                cell = [[TextImageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
                break;
            default:
                break;
        }
    }

    [cell setPerson:p];
    return cell;
}

這段代碼實現了根據不同的業務模型選取和顯示Cell的邏輯。但是這段代碼包含了重復代碼,switch case被調用了兩次。我們改進一下代碼:

第二次嘗試

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    BaseCell *cell;
    NSString *cellIdentifier;

    Class cellClass;
    switch (p.showtype) {
        case PersonShowText:
            cellClass = [TextCell class];
            break;
        case PersonShowAvatar:
            cellClass = [ImageCell class];
            break;
        case PersonShowTextAndAvatar:
            cellClass = [TextImageCell class];
            break;
        default:
            cellClass = [UITableViewCell class];
            break;
    }

    cellIdentifier = NSStringFromClass(cellClass);

    cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (!cell) {
        cell = [[cellClass alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }

    [cell setPerson:p];

    return cell;
}

這次比第一次的代碼看起來好了不少,通過一個通用的Class對象,來動態生成cell,避免了兩次調用switch case的重復代碼。但是,有沒有更好的實現方式?

第三次嘗試

- (void)viewDidLoad 
{
    ...
    [self registerCell];  //注冊cell
}
- (void)registerCell
{
    [_tableView registerClass:[TextCell class] forCellReuseIdentifier:NSStringFromClass([TextCell class])];
    [_tableView registerClass:[ImageCell class] forCellReuseIdentifier:NSStringFromClass([ImageCell class])];
    [_tableView registerClass:[TextImageCell class] forCellReuseIdentifier:NSStringFromClass([TextImageCell class])];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    Person *p = _persons[indexPath.row];
    BaseCell *cell;
    NSString *cellIdentifier;

    switch (p.showtype) {
        case PersonShowText:
            cellIdentifier = NSStringFromClass([TextCell class]);
            break;
        case PersonShowAvatar:
            cellIdentifier = NSStringFromClass([ImageCell class]);
            break;
        case PersonShowTextAndAvatar:
            cellIdentifier = NSStringFromClass([TextImageCell class]);
            break;
        default:
            cellIdentifier = NSStringFromClass([UITableViewCell class]);
            break;
    }

    cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    [cell setPerson:p];

    return cell;
}

可以看到,這次我們調用了 - (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier 方法,把tableView和cell先配置好,並且在cellForRowAtIndexPath方法裡面,去掉了if (!cell) {...}的處理,代碼看起來更加簡潔。

為什麼不再需要判斷cell是否為空?因為通過registerClass方法注冊了cell之後,dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath 方法會確保有一個可用的cell返回。

當然,我們可以把類型判斷的這段代碼提取出來,讓cellForRowAtIndexPath方法看起來更加簡潔

@interface Person : NSObject

......
@property (nonatomic, strong) NSString *cellIdentifier;

@end
@implementation Person

- (NSString *)cellIdentifier
{
    if (_showtype == PersonShowTextAndAvatar) {
        return NSStringFromClass([TextImageCell class]);
    } else if (_showtype == PersonShowAvatar){
        return NSStringFromClass([ImageCell class]);
    } else {
        return NSStringFromClass([TextCell class]);
    }
}

@end

現在cellForRowAtIndexPath方法看起來就像下面這樣,明顯簡潔多了

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    Person *p = _persons[indexPath.row];
    BaseCell *cell;
    NSString *cellIdentifier;

    cellIdentifier = p.cellIdentifier;

    cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    [cell setPerson:p];

    return cell;
}

結論:

使用 - (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath 可以讓UITableView處理多種類型的cell更加靈活和輕松。

訪問示例代碼



文章轉自 la0fu的簡書
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved