如何设置表视图单元附件视图以保留以前初始化的UIImageView?

时间:2010-07-06 22:22:43

标签: iphone uitableview uiimageview

假设我的视图控制器中有一个属性,定义如下:

@property (nonatomic, retain) UIImageView *checkmarkOffAccessoryView;

@synthesize在实施中,release-dealloc中,并在-viewDidLoad中初始化,如下所示:

self.checkmarkOffAccessoryView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"checkmarkOff.png"]] autorelease];

到目前为止一切顺利。

当我在我的表视图中使用它作为多个单元格的附件视图时,会发生两件事:

  1. 只有一个单元格的附件视图显示图像
  2. 应用程序用户界面冻结。
  3. 应用程序不会崩溃,因为我可以说,用户界面根本没有响应。这都在模拟器和设备上。

    以下是我如何将初始化属性与我的单元格一起使用:

    - (UITableViewCell *) tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
        // initialize or dequeue cell...
    
        if (condition)
            cell.accessoryView = self.checkmarkOffAccessoryView;
        else
            cell.accessoryView = nil;
    }
    

    使用上述代码,只有一个单元格显示附件视图,并且UI冻结。

    如果我直接在委托方法中初始化UIImageView实例,我会得到所有满足条件的单元格,显示附件视图,并且我没有遇到UI冻结:

    - (UITableViewCell *) tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
        // initialize or dequeue cell...
    
        if (condition)
            cell.accessoryView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"checkmarkOff.png"]] autorelease];
        else
            cell.accessoryView = nil;
    }
    

    我的目标是初始化尽可能少的对象并重用一个UIImageView。我很好奇为什么第一块代码是有问题的,我可以做些什么来解决这个问题。

    似乎单元格的accessoryView属性应该只增加retain self.checkmarkOffAccessoryView的{​​{1}}计数,但看起来我错过了一些细节。

    我忽略了什么?谢谢你的建议。

    修改

    我认为:

    self.checkmarkOffAccessoryView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"checkmarkOff.png"]] autorelease];
    

    与:

    相同
    UIImageView *uncheckedView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"checkmarkOff.png"]];
    self.checkmarkOffAccessoryView = uncheckedView;
    [uncheckedView release];
    

    无论哪种方式,我都会遇到相同的冻结症状。

4 个答案:

答案 0 :(得分:9)

您无法多次添加同一视图。 UI处理程序将疯狂。为了确保这一点,我试着按照你上面所说的做,我也遇到了同样的问题。 UI冻结,图像仅出现在其中一个单元格中。

你可以做的最好的事情是将你的图像存储为分配的UIImage,并有一个帮助函数,每个单元格返回一个新的UIImageView。

使用您当前的方法(没有存储的UIImage),您可能会这样做:

-(UIImageView *) makeCheckmarkOffAccessoryView
{
    return [[[UIImageView alloc] initWithImage:
        [UIImage imageNamed:@"checkmarkOff.png"]] autorelease];
}

然后再做

cell.accessoryView = [self makeCheckmarkOffAccessoryView];

您可能知道,另一方面,UIImages可能会被使用多次。 UIImageView不占用大量空间,因此您可以轻松拥有一堆而不用担心。

要扩展一个地方的交易,想象你同时在两个地方添加一个UIView。

[ob removeFromSuperview]会为此对象做些什么?它会从两个地方删除视图吗?只从他们中的一个?请求[ob superview]时会返回哪个值?很明显,用户界面并不是为了处理您所要求的内容。

答案 1 :(得分:0)

尝试在初始化程序中没有自动释放。我怀疑你过度释放了。

顺便说一下,你的控制台在冻结时可能会显示BAD_ACCESS错误。如果你打开NSZombieEnabled,我猜你会看到它正在调用一个解除分配的UIImage。

答案 2 :(得分:0)

也许这会有所帮助

- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    static NSString *CellIdentifier = @"ShoppingListCell";

    HSShoppingListCell *cell = (HSShoppingListCell *)[aTableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        [[NSBundle mainBundle] loadNibNamed:@"ShoppingListCell" 
                                                                            owner:self 
                                                                        options:nil];
        cell = shoppingListCell;
    }

    ShoppingListItem *theItem = nil;
    theItem = [self.fetchedResultsController objectAtIndexPath:indexPath];

    UIImage *selected         = [UIImage imageNamed:@"listBullet_checked.png"];
    UIImage *notSelected    = [UIImage imageNamed:@"listBullet.png"];

    cell.imageView.image = ([theItem.checkedOff boolValue] ? selected : notSelected); 

    cell.shoppingListLabel.text = theItem.productName;
    [cell.shoppingListLabel setFont:[UIFont fontWithName:@"Marker Felt" size:26.0]];
    return cell;
}

- (void)toggleCellImage:(NSIndexPath *)indexPath
{
    ShoppingListItem *item  = [self.fetchedResultsController objectAtIndexPath:indexPath];

    item.checkedOff = ([item.checkedOff boolValue] ? [NSNumber numberWithBool:NO] : [NSNumber numberWithBool:YES]);

    [HSCoreDataUtilities saveContext:item.managedObjectContext];
    [self.tableView reloadData];
}

#pragma mark -
#pragma mark Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{
    [self toggleCellImage:indexPath];
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}

答案 3 :(得分:0)

将你的情况减少到最基本要求(我建议在UIView周围放置两个'瘦'UIImageView个对象......)我发现这很可能是不可能的。< / p>

在IB中创建2个空UIView个对象,将它们连接到bareView1bareView2。然后

UIImageView *imageView = [[UIImageView alloc]
                      initWithImage:[UIImage imageNamed:@"test.png"]];
[bareView1 addSubview:imageView]; // it shows either here ...
[bareView2 addSubview:imageView]; // ... or here

你永远不能在这样的情况下多次获得图像。根据经验,我认为 not 继承自UIView的第一个对象可以多次使用,即UIImage。与Kalle所说的一样,UIView在视图层次结构中只能有一个父级。

延迟第二个addSubview只会使UIImageViewbareView1跳转到bareView2

冻结可能是因为事件处理混淆了:附件可以是交互式的,如果它们是同一个对象,你怎么知道哪一个被轻敲?所以代码假设对象是唯一的,并且你设法违反了这个假设。