文本编辑后更新时 UITableView 崩溃

发布于 2024-09-07 22:38:30 字数 1858 浏览 4 评论 0原文

所以我完全被这个问题难住了,并想称之为“操作系统错误”。

我有一个带有单个部分的 TableView 控制器,并且在该部分的标题中有一个 UITextField。有几个操作可以毫无问题地添加/删除行。但是,一旦在标题中编辑文本并且关闭键盘,任何行的插入/删除都会立即导致崩溃。

实际上可以进一步简化 - 一旦键盘关闭,只需在桌子上调用 beginUpdates/endUpdates 就足以导致崩溃。调用堆栈的结尾是:

_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;
}

So I'm totally stumped by this one and tempted to call "OS bug".

I have a TableView controller with a single section, and in the header for that section there is an UITextField. Several operations result in rows being added/removed without a problem. However, as soon as text is edited in the header, and the keyboard dismissed, any insertion/removal of rows results in an immediate crash.

And it can actually be simplified further - simply calling beginUpdates/endUpdates on the table once the keyboard is dismissed is enough to cause a crash. The end of the callstack is:

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

I've put together a minimal example that demonstrates the problem.

Complete Controller source: http://www.andrewgrant.org/public/TableViewFail.txt

Example Project: http://www.andrewgrant.org/public/TableViewCrash.zip

Most relevant code:

- (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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

顾北清歌寒 2024-09-14 22:38:30

只是更新 - 我向 Apple 提交了错误报告和重现案例,他们确认这是 iOS 4.0 中的错误。截至 iOS 4.1 beta 2,该问题尚未得到修复。

我的解决方法是将表格的第一行转换为伪标题,该标题占据整个内容视图并具有自定义高度。它不是那么好(例如,东西无法到达屏幕边缘),但它很接近并且不会崩溃。

Just an update - I submitted a bug report and repro case to Apple and they confirmed it's a bug in iOS 4.0. As of iOS 4.1 beta 2 it had not been fixed.

My work around was to turn the first row of my table into a pseudo header that occupies the entire content view and has a custom height. It's not quite as good (things cant reach to the edge of the screen for example) but it's close and doesn't crash.

那小子欠揍 2024-09-14 22:38:30

我昨晚遇到了这个错误,今天早上花了几个小时试图解决它。该线程中的其他答案对我不起作用,但确实帮助我想出了一个我认为最好的解决方法。

Cameron 建议将屏幕外 UITextField 设置为firstResponder,然后在调用 tableview 上的 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

I hit this bug last night and spent a few hours this morning trying to figure it out. The other answers in this thread didn't work for me, but did help me come up with a workaround that I think is best.

Cameron suggested making an offscreen UITextField the firstResponder, then resigning it before calling endUpdates on the tableview. This didn't work for me, but it gave me an idea.

In the context of my custom header view, I re-parent the text field (in my case, a UISearchBar, actually) before calling resignFirstResponder. Then I put it back:

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

a few lines later, when I call [tableView endUpdates], it no longer crashes.

Edit: It just got a bit more complicated. The problem is that if first-responder status is otherwise revoked (for example, the user dismisses the keyboard), this parent-swapping code isn't executed, and we'll eventually get the crash. My current fix is to place a category-override on UITextField resignFirstResponder -- seems to work but not sure yet if there are any adverse side effects.

@implementation UITextField (private)

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

@end
纵性 2024-09-14 22:38:30

进一步了解 Tom 的解决方案,我注意到该解决方案仅适用于 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

Taking Tom's solution one step further, I noticed this solution only works on iOS 4.X, which is ok because this problem only exists in iOS 4.X. Therefore I changed his method to:

@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
虫児飞 2024-09-14 22:38:30

我自己也遇到过这个错误,很高兴找到你的帖子,因为我正在用头撞桌子,试图找出我哪里搞砸了。

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

I came across this bug myself and am so glad I found your post because I was banging my head on my desk trying to figure out where I screwed up.

For my workaround, I created an offscreen UITextField and called becomeFirstResponder and then resignFirstResponder on that text field before doing the updates. This avoided the crash and didn't require any redesign of the headers or cells.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文