UITableView与自定义UITableViewCell无法正常显示

时间:2011-03-20 04:02:51

标签: cocoa-touch uitableview subclass

我有一个自定义UITableViewCell(实际上我已经为不同的表分了几次),偶尔表会开始“降级”并慢慢崩溃。重现崩溃是不可能的,它会在以下调用堆栈中崩溃:

特定应用信息:
订单远程无法及时恢复

经过的总CPU时间(秒):0.240(用户0.040,系统0.200),12%CPU
经过的应用程序CPU时间(秒):0.000,0%CPU

Thread 0:
0   libSystem.B.dylib               0x310932b8 semaphore_wait_trap + 8  
1   libSystem.B.dylib               0x310c0b46 semaphore_wait + 2  
2   libSystem.B.dylib               0x3116a7c4 _dispatch_semaphore_wait_slow + 296  
3   libSystem.B.dylib               0x31169cb4 _dispatch_barrier_sync_f_slow + 128  
4   CoreFoundation                  0x3042bb70 __CFMachPortPerform + 92  
5   CoreFoundation                  0x304236f8 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 20  
6   CoreFoundation                  0x304236bc __CFRunLoopDoSource1 + 160  
7   CoreFoundation                  0x30415f76 __CFRunLoopRun + 514  
8   CoreFoundation                  0x30415c80 CFRunLoopRunSpecific + 224  
9   CoreFoundation                  0x30415b88 CFRunLoopRunInMode + 52  
10  GraphicsServices                0x31eec4a4 GSEventRunModal + 108  
11  GraphicsServices                0x31eec550 GSEventRun + 56  
12  UIKit                           0x313cf322 -[UIApplication _run] + 406  
13  UIKit                           0x313cce8c UIApplicationMain + 664  
14  Order Remote                    0x00002a02 0x1000 + 6658  
15  Order Remote                    0x000029cc 0x1000 + 6604  

这就是崩溃时的样子......

http://img819.imageshack.us/i/uitableviewmissingdata2.jpg/

http://img220.imageshack.us/i/uitableviewmissingdata1.jpg/

我已经浏览了所有内存管理代码并启用了僵尸,并检查了我如何将单元格子类化,我无法看到我出错的地方。请帮帮我。

...

这是一些代码

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    MenuItemCell *cell = (MenuItemCell *)[tableView dequeueReusableCellWithIdentifier:@"MenuItemCell"];
    if (cell == nil) 
    {
        cell = [[[MenuItemCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"MenuItemCell"] autorelease];
        DLog( @"MenuViewController::cellForRowAtIndexPath: allocating memory for a MenuItemCell" );
    }
    else
    {
        DLog( @"MenuViewController::cellForRowAtIndexPath: dequeuing an existing MenuItemCell for reuse" );
    }

    cell.accessoryType =  UITableViewCellAccessoryNone;

    // only display the item modifiers view if the item has one or more modifiers
    if( [[selectedCategory getModifiers] count] > 0 )
    {
        cell.accessoryType =  UITableViewCellAccessoryDetailDisclosureButton;
    }

    // Configure the cell.
    cell.textLabel.text = [[items objectAtIndex:indexPath.row] name];

    // build a mutable string from the modifiers and set the text to the result in the detail label
    NSMutableString* modifiers = [[NSMutableString alloc] initWithString:@""];
    Item* i = [items objectAtIndex:indexPath.row];

    for( ItemModifier* modifier_iterator in [i modifiers] )
    {
        [modifiers appendString: [modifier_iterator name]];
        [modifiers appendString: @" "];
    }

    cell.detailTextLabel.text = modifiers;

    [modifiers release];
    modifiers = nil;

    [cell setItem: i];

    return cell;
}

@interface MenuItemCell:UITableViewCell     {         UILabel * itemCount;     }

- (void) setItem: (Item*) item;
- (void) resetItemCount;

@end

@implementation MenuItemCell

- (id) initWithStyle: (UITableViewCellStyle) style reuseIdentifier: (NSString*) reuseIdentifier
{
    if( (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) )
    {
        itemCount = [[UILabel alloc] initWithFrame:CGRectZero];
        [[self contentView] addSubview:itemCount];
    }

    return self;
}

- (void) resetItemCount
{
    [itemCount setText: @""];
    [self setNeedsDisplay];
}

- (void) layoutSubviews
{
    [super layoutSubviews];

    float inset = 10.0;
    CGRect bounds = [[self contentView] bounds];
    float h = bounds.size.height;
    float w = bounds.size.width;

    CGRect accessoryViewBounds;

    if( !self.accessoryView )
    {
        accessoryViewBounds = CGRectZero;
    }
    else 
    {
        accessoryViewBounds = self.accessoryView.bounds;
    }

    CGRect textLabelBounds = self.textLabel.bounds;

    CGRect innerFrame = CGRectMake( round( inset + w / 2), textLabelBounds.origin.y, round( w / 2 - accessoryViewBounds.size.width - inset * 3 ), h - 1 );

    if( ( innerFrame.size.height >= bounds.size.height ) || ( innerFrame.size.width >= bounds.size.width ) )
    {
        [NSException raise:@"inner frame for MenuItemCell is larger than the contentView bounds" format:@"MenuItemCell (w: %d h: %d) contentView (w: %d h: %d)", innerFrame.size.width, innerFrame.size.height, bounds.size.width, bounds.size.height];
    }

    // move the rectange to the right side of the cell
    itemCount.textAlignment = UITextAlignmentRight;
    itemCount.textColor = [UIColor redColor];
    itemCount.highlightedTextColor = [UIColor whiteColor];
    itemCount.font = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];

    [itemCount setFrame: innerFrame];
}

- (void) setItem: (Item*) item
{
    if( [item count] > 0 )
    {
        [itemCount setText: [NSString stringWithFormat: @"%d", [item count]]];
    }
    else 
    {
        [itemCount setText: @""];
    }

    [self setNeedsDisplay];

    DLog( @"MenuItemCell::itemCount %@ %d", [item name], [item count] );
}

- (void) dealloc
{
    [itemCount release];
    itemCount = nil;

    [super dealloc];
}

@end

1 个答案:

答案 0 :(得分:0)

问题可能是(我无法确认,因为行为是如此不稳定和不可重现)与未在viewDidUnload中释放IBOutlet定义的指针有关。在重新阅读文档之前,我没有意识到他们被保留了。

我还将所有简单的访问器更改为@properties,而不是定义自己的访问器以降低躲避内存管理技术的风险。

...

@interface MenuViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
    IBOutlet UITableView* itemsTable;
    NSMutableArray* items;

    Category* selectedCategory;
    Order* editingOrder;
    NSIndexPath* selectedRow;

    BOOL addItemToExistingOrder;
}

-(id)initWithCategory: (Category*)category;
-(IBAction)addItem: (id)sender;

@property (assign) Category* selectedCategory;    
@property (assign) NSMutableArray* items;    
@property (assign) Order* editingOrder;    
@property (assign) BOOL addItemToExistingOrder;    

@implementation
- (void)viewDidUnload
{    
    [super viewDidUnload];

    [selectedRow release];
    selectedRow = nil;

    [itemsTable release];
    itemsTable = nil;
}