UISearchBar исчезает из tableHeaderView при использовании beginUpdates/endUpdates

У меня есть контроллер табличного представления с UISearchController, который устанавливает UISearchBar как tableView.tableHeaderView. При обновлении результатов поиска я использую beginUpdates и endUpdates и связанные с ними методы для обновления данных для представления таблицы.

Это приведет к исчезновению строки поиска; tableHeaderView устанавливается в пустой, общий UIView того же размера, что и строка поиска. Если я просто использую reloadData вместо целой процедуры beginUpdates/endUpdates, все в порядке.

Контроллер табличного представления встроен в обычный контроллер вида; в нем нет контроллера навигации. Это вся реализация контроллера табличного представления, необходимого для воспроизведения проблемы:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
    self.searchController.searchResultsUpdater = self;
    self.searchController.dimsBackgroundDuringPresentation = NO;

    self.tableView.tableHeaderView = self.searchController.searchBar;
}

- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
    [self.tableView beginUpdates];
    [self.tableView endUpdates];
}

Почему это приводит к замене строки поиска пустым представлением и как ее можно избежать?

Ответ 1

Когда вы сначала нажимаете UISearchController's searchBar, для анимации SearchBar требуется около 0,5 с. Но self.tableView.endUpdates() сразу вызывался методом делегата, анимация была прервана.
SearchBar застрял в середине анимации, и вы не видите его UI:
введите описание изображения здесь

Обходной путь - проверить, находится ли searchBar в анимации, и задержать self.tableView.endUpdates(), когда он находится.

func updateSearchResultsForSearchController(searchController: UISearchController){
    self.tableView.beginUpdates()
    //Do some updates

    if !searchController.searchBar.showsCancelButton{
        self.tableView.performSelector(#selector(UITableView.endUpdates), withObject: nil, afterDelay: 1)

    }else{
        self.tableView.endUpdates()
    }
}

Ответ 2

Небольшая версия о beginUpdates, endUpdates and reloadData

beginUpdates:: начинается серия вызовов методов, которые вставляют, удаляют или выбирают строки и разделы представления таблицы. Вызовите этот метод, если вы хотите, чтобы последующие операции вставки, удаления и выбора (например, cellForRowAtIndexPath: и indexPathsForVisibleRows) анимировались одновременно. Вы также можете использовать этот метод, за которым следует метод endUpdates, чтобы анимировать изменение высоты строки без перезагрузки ячейки. Эта группа методов должна заканчиваться вызовом endUpdates. Эти пары методов могут быть вложенными. Если вы не совершаете вызовы вставки, удаления и выбора внутри этого блока, атрибуты таблицы, такие как количество строк, могут стать недействительными. Вы не должны вызывать reloadData внутри группы; если вы вызываете этот метод внутри группы, вы должны сами выполнять анимацию.

endUpdates: Завершает ряд вызовов методов, которые вставляют, удаляют, выбирают или перезаписывают строки и разделы представления таблицы. Вы вызываете этот метод, чтобы скопировать ряд вызовов методов, который начинается с beginUpdates и состоит из операций по вставке, удалению, выбору и перезагрузке строк и разделов табличного представления. Когда вы вызываете endUpdates, UITableView анимирует операции одновременно. Вызовы beginUpdates и endUpdates могут быть вложенными. Если вы не совершаете вызовы вставки, удаления и выбора внутри этого блока, атрибуты таблицы, такие как количество строк, могут стать недействительными.

reloadData: Перезагружает строки и разделы представления таблицы. Вызовите этот метод для перезагрузки всех данных, которые используются для построения таблицы, включая ячейки, верхние и нижние колонтитулы разделов, массивы индексов и т.д. Для эффективности в представлении таблицы отображаются только те строки, которые видны. Он корректирует смещения, если таблица сжимается в результате перезагрузки. Представление делегата таблицы или источника данных вызывает этот метод, когда он хочет, чтобы представление таблицы полностью перезагрузило свои данные. Он не должен вызываться в методах, которые вставляют или удаляют строки, особенно в блоке анимации, реализованном с вызовами beginUpdates и endUpdates.

Теперь в случае поиска мы не знаем, какие строки будут влиять, а также каждый раз, когда результаты поиска будут отличаться, я считаю, что не следует использовать

[self.tableView beginUpdates];
[self.tableView endUpdates];

поскольку он используется при выполнении операции insert, update or delete в tableview, и вы знаете ее indexPath.

Лучше использовать [self.tableView reloadData];, поскольку он будет обновлять только видимые строки или раздел в виде таблицы. Также см. Образец кода Apple для Поиск таблиц с помощью UISearchController, также рекомендуется использовать reloadData.

Внесите соответствующие изменения, и вам хорошо идти.

Счастливое кодирование:)