Сбой UITableView при обновлении после редактирования текста - PullRequest
4 голосов
/ 06 июля 2010

Так что я полностью озадачен этим и испытываю желание вызвать «ошибку ОС».

У меня есть контроллер 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;
}

Ответы [ 4 ]

1 голос
/ 18 февраля 2011

Я ударил эту ошибку прошлой ночью и провел несколько часов этим утром, пытаясь понять это. Другие ответы в этой теме не помогли мне, но помогли мне найти обходной путь, который я считаю лучшим.

Кэмерон предложил сделать UITextField вне экрана firstResponder, а затем отказаться от него перед вызовом endUpdates в табличном представлении. Это не сработало для меня, но дало мне идею.

В контексте моего пользовательского представления заголовка я переопределяю текстовое поле (на самом деле, в моем случае, UISearchBar) перед вызовом resignFirstResponder. Затем я положил его обратно:

[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
1 голос
/ 19 августа 2010

Просто обновление - я отправил отчет об ошибке и репро в Apple, и они подтвердили, что это ошибка в iOS 4.0.Начиная с iOS 4.1 beta 2 это не было исправлено.

Моя работа заключалась в том, чтобы превратить первую строку моей таблицы в псевдо заголовок, который занимает весь вид содержимого и имеет собственную высоту.Это не так хорошо (например, вещи не доходят до края экрана), но оно близко и не падает.

0 голосов
/ 14 ноября 2011

Идя дальше к решению Тома, я заметил, что это решение работает только на 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
0 голосов
/ 26 января 2011

Я сам столкнулся с этой ошибкой и очень рад, что нашел ваш пост, потому что я бился головой о стол, пытаясь выяснить, где я облажался.

Для моего обходного пути я создал закадровый UITextField и вызвал becomeFirstResponder, а затем resignFirstResponder в этом текстовом поле перед выполнением обновлений. Это позволило избежать сбоя и не потребовало перепроектирования заголовков или ячеек.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...