复制UITableViewCell

时间:2009-02-20 20:43:26

标签: ios objective-c iphone uitableview cocoa-touch

我正在从nib文件中读取tableView:cellForRowAtIndexPath:中的自定义表格单元格。这对我的目的很有用,除非它很慢。

现在,我知道从长远来看,正确的做法是在代码中完全创建单元格,并使用单个视图,等等。但这是一个原型,我不想付出太多努力。

现在,如果我只在UIViewController子类中读取一次nib,然后tableView:cellForRowAtIndexPath:复制它,我会很高兴。我的假设是复制比读取笔尖要快。

以下是我用来加载笔尖的内容,我从viewDidLoad:(以及retain之后调用)

-(id)loadFromNamed:(NSString*)name {
    NSArray *objectsInNib = [[NSBundle mainBundle] loadNibNamed:name
                                                          owner:self
                                                        options:nil];
    assert( objectsInNib.count == 1 );
    return [objectsInNib objectAtIndex:0];
}

到目前为止一切都很好。但问题是:我如何反复复制?它甚至可能吗?

我尝试[_cachedObject copy][_cachedObject mutableCopy],但UITableViewCell不支持任何副本协议。

如果必须,我可以告诉他们忽略速度,直到我准备完全取下笔尖,但如果这里有一个低悬的水果,我宁愿让它快一点。

有什么想法吗?

5 个答案:

答案 0 :(得分:8)

我认为表格单元的复制可以与出列机制一起使用,这将允许创建单元格一次(从笔尖或编程或从其他笔尖自动加载并在IB中作为插座链接)然后克隆它或在需要时将其出列。

UITableViewCell不符合NSCopying协议,但它支持密钥存档/解压缩机制,因此可用于克隆。

根据答案“ How to duplicate a UIButton in Objective C?“我的数据源委托方法如下:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellID = @"CellIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellID];

    if (!cell) {
        NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject:self.tableViewCell];
        cell = [NSKeyedUnarchiver unarchiveObjectWithData:archivedData];
    }

    // ... config ...

    return cell;
}

在我的情况下, self.tableViewCell 是从视图的nib文件中加载一次的单元格。

我没有测试什么会更快:“archive + unarchive”克隆或“加载nib文件+ unarchive”哪个框架将在 -loadNibNamed:owner:options:的情况下执行,我只是考虑到方便性而使用这种方法,但内存操作与文件操作的可能性会更快。

编辑:看起来并不像最初看起来那么容易。由于UIImage不符合NSCoding,因此无法在没有其他代码的情况下复制具有已配置的UIImageViews的单元格。是的,复制整个图像绝对不是一个好习惯,为苹果指责这一点欢呼。

答案 1 :(得分:6)

使用表视图中内置的单元格克隆。 Apple知道生成很多表格单元格很慢。查看此方法的文档:

- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier

您创建一次单元格,然后在请求新单元格时,使用该方法克隆现有单元格。然后,您只需更改有关新单元格的更改内容并返回单元格对象。

另请查看Apple提供的表格视图实际示例代码,该代码使用此方法并以正确的方式显示。你的细胞从笔尖装入的事实根本不重要。


轻微澄清:我不认为上面的方法为您克隆细胞。相反,它需要滚动屏幕的单元格对象,只需将它们移动到新的位置即可。所以它真的重复使用一个细胞。因此,请确保您的自定义表视图可以设置为初始化之外所需的所有新值。

答案 2 :(得分:4)

不为这个解决方案感到自豪,但它适用于最大数量的可能的IB绑定:

接口(AlbumTableViewCell是UITableViewCell的子类,其实例在AlbumViewController的XIB文件中定义):

@interface AlbumsViewController : UITableViewController {
    IBOutlet AlbumTableViewCell *tableViewCellTrack;
}

@property (nonatomic, retain) AlbumTableViewCell *tableViewCellTrack;

实现(unarchive / archive会复制/克隆表视图单元格):

@implementation AlbumsViewController

@synthesize tableViewCellTrack;

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    AlbumTableViewCell *cell = (AlbumTableViewCell *)[tableView dequeueReusableCellWithIdentifier: @"AlbumCell"];

    if (cell == nil) {
        AlbumsViewController *albumsViewController = [[[AlbumsViewController alloc] init] autorelease];
        [[NSBundle mainBundle] loadNibNamed: @"AlbumsViewController" owner: albumsViewController options: nil];

        cell = albumsViewController.tableViewCellTrack;
    }

    cell.labelTitle.text = ...;
    cell.labelArtist.text = ...;

    return cell;
}

答案 3 :(得分:3)

好吧,我不确定为什么所有教程都没有指定这一步。

在Nib中使用自己的自定义UITableViewCell时,调用dequeueReusableCellWithIdentifier是不够的。您必须在IB中指定“标识符”,只需在“表视图单元格”选项卡部分中指定它。

然后确保您在IB中输入的标识符与您用于dequeueReusableCellWithIdentifier的标识符相同。

答案 4 :(得分:1)

这是在Swift中

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    var cell : UITableViewCell?
    let cellId = String(format: "Cell%d", indexPath.row)
    cell = alertTable!.dequeueReusableCellWithIdentifier(cellId) as! UITableViewCell?

    if cell == nil {
        let archivedData = NSKeyedArchiver.archivedDataWithRootObject(masterTableCell!)
        cell = NSKeyedUnarchiver.unarchiveObjectWithData(archivedData) as! UITableViewCell?
    }

    // do some stuff

    return cell!
}