2010-07-05 75 views
4

所以我完全被这个人难住,并试图称之为“操作系统错误”。文本编辑后更新UITableView崩溃

我有一个TableView中控制器具有单个部分,并且在该节的报头存在的UITextField。几个操作会导致行被添加/删除而不会出现问题。但是,只要文本在标题中被编辑,并且键盘被解散,任何插入/删除行都会立即崩溃。

它实际上可以进一步简化 - 简单地调用在桌子上beginUpdates/endUpdates一旦键盘被驳回,就足以导致崩溃。 callstack的结尾是:

_CFTypeCollectionRetain 
_CFBasicHashAddValue 
CFDictionarySetValue 
-[UITableView(_UITableViewPrivate) _updateWithItems:withOldRowData:oldRowRange:newRowRange:context:] 
-[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:] 
-[UITableView endUpdates] 

我已经放在一起演示了这个问题的一个最小的例子。

完成控制器来源:http://www.andrewgrant.org/public/TableViewFail.txt

示例项目:http://www.andrewgrant.org/public/TableViewCrash.zip

最相关的代码:

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 
{ 
    // create header view 
    UIView* header = [[[UIView alloc] initWithFrame:CGRectMake(0.f, 0.f, 320.f, 50.f)] autorelease]; 

    // text field 
    UITextField* textField = [[[UITextField alloc] initWithFrame:CGRectMake(10.f, 12.f, 300.f, 28.f)] autorelease]; 
    textField.text = @"Edit, then 'Save' will crash"; 
    textField.borderStyle = UITextBorderStyleRoundedRect; 
    textField.clearButtonMode = UITextFieldViewModeAlways; 
    textField.delegate = self; 

    [header addSubview:textField]; 

    return header; 
} 

- (BOOL)textFieldShouldReturn:(UITextField *)textField 
{ 
    // no purpose, but demonstrates updates work at this point 
    [self.tableView beginUpdates]; 
    [self.tableView endUpdates]; 

    [textField resignFirstResponder]; 

    // immediate crash 
    [self.tableView beginUpdates]; 
    [self.tableView endUpdates]; 
    return YES; 
} 
+0

值得注意的是 - 无论textField委托是控制器还是完全不相关的对象实例,都会发生崩溃。 – 2010-07-05 20:34:28

+0

我看着你的项目。它在3.x中运行正常,但正如你所说的,当你点击保存时它会在4.0上崩溃。 +1对于棘手的问题:) – Kalle 2010-07-05 21:02:19

+1

想到的一件事是,你的XIB文件有一个表视图,它指向RootViewController作为它的数据源和委托,而根视图控制器反过来实例化一个TableViewFail实例并将其设置为“on最佳”。不应该是一个问题,但你有两张桌子堆叠在一起。 – Kalle 2010-07-05 21:18:46

回答

1

只是一个更新 - 我提交了一个bug报告,并摄制情况下苹果和他们确认这是iOS 4.0中的一个错误。从iOS 4.1 beta 2开始,它尚未修复。

我的工作是围绕把我的表的第一行成伪标头,占据了整个内容视图,并有一个自定义的高度。它不是很好(例如不能到达屏幕边缘),但它很接近,不会崩溃。

+0

废话。我也被这个烧了。 – TomSwift 2011-02-18 17:27:26

+0

你有雷达吗? – TomSwift 2011-02-18 17:40:40

0

我碰到这个错误就我和我很高兴,我发现您的文章,因为我敲我的头放在我的桌子试图找出在那里我搞砸了。

对于我的解决方法,在更新之前,我在该文本字段上创建了屏幕外屏幕UITextField并调用becomeFirstResponder,然后resignFirstResponder。这避免了崩溃,并且不需要重新设计标题或单元格。

+0

我试过这个,它不适合我。我想我做了你所描述的 - 创建一个UITextField,我将它附加到应用程序的窗口,但是被隐藏起来。称为[tf becomeFirstResponder],然后是[tf resignFirstResponder] - 都成功(并且键盘滑动)。但是在几行后面调用[tableView endUpdates]时我仍然崩溃。你有没有更多的提示? – TomSwift 2011-02-18 17:36:14

+0

这就是我最终做的:'[hiddenField becomeFirstResponder];\t \t [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(dismissKeyboard :) userInfo:nil repeats:NO];'并简单地在关闭键盘中调用resignFirstResponder – Cameron 2011-03-23 18:20:24

1

昨晚我打了这个bug,今天早上花了几个小时试图弄清楚。在这个线程中的其他答案对我来说不起作用,但确实帮助我提出了一种我认为是最好的解决方法。

卡梅隆建议制作一个屏幕外的UITextField的firstResponder,然后在实现代码如下调用endUpdates前辞职了。这不适合我,但它给了我一个主意。

在我的自定义标题视图的情况下,我呼吁resignFirstResponder前重新父文本字段(对我来说,一个UISearchBar,实际上)。然后我把它放回去:

[self.window addSubview: sb]; 
[sb resignFirstResponder]; 
[self addSubview: sb]; 

几行后,当我调用[tableView endUpdates]时,它不再崩溃。

编辑:它只是有点复杂。问题是,如果第一响应者的状态被撤销(例如,用户关闭了键盘),这个父交换代码不会被执行,我们最终会得到崩溃。我目前的解决方法是在UITextField resignFirstResponder上放置一个类别覆盖 - 似乎工作,但如果有任何不良副作用,还不确定。

@implementation UITextField (private) 

- (BOOL) resignFirstResponder 
{ 
    UIView* superviewSave = self.superview; 
    [self.window addSubview: self]; 
    BOOL success = [super resignFirstResponder]; 
    [superviewSave addSubview: self]; 
    return success; 
} 

@end 
0

以汤姆的解决方案一步,我注意到了这个解决方案仅适用于iOS 4.X,这是确定的,因为这个问题只在iOS中4.X.存在因此,我将他的方法更改为:

@implementation customUITextField 

- (BOOL)resignFirstResponder { 

if ([[UIDevice currentDevice].systemVersion characterAtIndex:0] == '4') { 

    UIView* superviewSave = self.superview; 
    [self.window addSubview:self]; 
    BOOL success = [super resignFirstResponder]; 
    [superviewSave addSubview:self]; 
    return success; 

} 

return [super resignFirstResponder]; 

} 

@end