带有自定义 UITableViewCell 的 UITableView 无法正确显示
我有一个自定义的 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
I have a custom UITableViewCell
(actually I have subclassed it a few times for different tables) and occasionally the table will start to "degrade" and slowly crash. It is impossible to reproduce the crash and it crashes with the following call stack:
Application Specific Information:
Order Remote failed to resume in time
Elapsed total CPU time (seconds): 0.240 (user 0.040, system 0.200), 12% CPU
Elapsed application CPU time (seconds): 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
Here is what it looks like when it it about to crash...
http://img819.imageshack.us/i/uitableviewmissingdata2.jpg/
http://img220.imageshack.us/i/uitableviewmissingdata1.jpg/
I've been through all my memory management code and enabled zombies and checked how I subclass the cell and I can't see where I am going wrong. Please help me.
...
here is some code
- (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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题可能(我无法确认,因为行为非常不稳定且不可重现)与未释放 viewDidUnload 中 IBOutlet 定义的指针有关。我没有意识到它们被保留,直到重新阅读文档。
我还将所有简单的访问器更改为 @properties,而不是定义自己的访问器,以降低内存管理技术的风险。
The problem was probably (I can't confirm because the behaviour was so erratic and non-reproducable) related to not releasing IBOutlet defined pointers in viewDidUnload. I didn't realise that they were retained until re-reading the docs.
I also changed all of my simple accessors to @properties rather than defining my own to reduce the risk of dodgy memory management techniques.