2012-03-12 4 views
1

Мое приложение имеет UITableViewController, который получает «Недопустимое обновление: недопустимое количество строк в разделе 0 ...» после добавления строк. Дело в том, что это происходит только в% 0,2 сеансов. Наше приложение имеет миллионы сеансов, поэтому сбои складываются.UITableView случайный сбой при добавлении строк

Поток прост. Это часть функции, которая соответствует музыке пользователя с нашим каталогом видео. Фоновая нить выполняет ряд запросов. Запрос исчезает, ответ возвращается с результатами, затем эти результаты добавляются в таблицуView на одной из наших вкладок. Запросы идут в партиях и могут содержать множество результирующих строк. Поэтому вместо вызова reloadData после того, как пакет входит, я хотел бы добавить их правильно. Работает потрясающе, но иногда падает.

Я смог воспроизвести это один раз на устройстве. Это никогда не происходило на симуляторе. Насколько я знаю, авария достаточно случайна, хотя в основном это происходит на 3gs. Наименьшее количество аварий приходится на 4s.

Вот код. Ответ возвращается. В этом случае allMatches - это каждое совпадение до сих пор (источник данных для таблицы). batchMatches - количество новых исполнителей. Оба являются массивами:

[self.tableView beginUpdates]; 
    NSMutableArray *paths = [[NSMutableArray alloc] init]; 
    for (int i = [allMatches count] - [batchMatches count]; i < [allMatches count]; ++i) { 
     NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];   
     [paths addObject: indexPath]; 
    } 
    [self.tableView insertRowsAtIndexPaths:paths withRowAnimation:NO]; 
    [self.tableView endUpdates]; 
    [paths release]; 

Код довольно прост. Он просто добавляет строки в конец, по одному для каждого результата. Никогда не удаляется. Примером полного сообщения об исключении является «Недопустимое обновление: недопустимое количество строк в разделе 0. Количество строк, содержащихся в существующем разделе после обновления (131), должно быть равно количеству строк, содержащихся в этом разделе перед обновлением (131), плюс или минус количество строк, вставленных или удаленных из этого раздела (20 вставленных, 0 удаленных) и плюс или минус количество строк, перемещенных в или из этого раздела (0 перемещен, 0 перемещен). " Числа повсюду в реальных отчетах о сбоях, поэтому это не определенный номер партии.

Как я уже сказал, он почти всегда работает. И он падает обычно на 3GS. Мне интересно, может ли это быть ошибкой структуры. Я всегда мог вызывать reloadData после каждой партии, но это приводит к уродливому миганию ячеек таблицы каждый раз. С целью я вызвал исключение, и, похоже, после этого таблица мертва, поэтому я не смог сделать try/catch с reloadData как резерв в блоке catch.

Может ли кто-нибудь пролить некоторый свет? Извинения за длину этого поста.

EDIT: запросы сервера выполняются с использованием NSOperationQueue, поэтому они находятся на фоновом потоке. Когда ответ возвращается, я отправляю уведомление по основному потоку, из-за чего запускается код таблицы. Уведомление опубликовано так:

NSNotification *notification = [NSNotification notificationWithName:notificationName object:self]; 
[self performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO]; 

Сообщение notificiation просто обертка [[NSNotificationCenter defaultCenter] postNotification: уведомление]. Таким образом, код таблицы должен быть в основном потоке.

ответ

1

Я предполагаю, что вы выполняете обновление вида таблицы в фоновом потоке. Вы должны сделать это в основном потоке.

Поместите свой код внутри блока dispatch_async.

dispatch_async(dispatch_get_main_queue(), ^(void) { 
     // .. 
}); 
+0

Эй, большое спасибо за ответ. Я добавил свой вопрос, чтобы объяснить, что код таблицы работает в основном потоке. В фоновом режиме работает только взаимодействие с сервером. Я выбрал другой подход, чем вы. Я использую NSOperationQueue для запуска связи с сервером. Затем NSNotification отправляется из потока bg через performSelectorOnMainThread. Поэтому noitifcation отправляется в основной поток.Затем ViewController получает это уведомление, которое должно быть в основном потоке, который обновляет таблицу. Вы видите какие-либо проблемы с моим подходом к вашему? Еще раз спасибо. –

+0

Я не вижу разницы между обоими подходами. Оба выполняют асинхронный код в основном потоке. Убедитесь, что массив данных не может быть изменен фоновым потоком при обновлении таблицы. Чтобы быть в безопасности, вы можете отправить уведомление синхронно. Просто установите waitUntilDone на YES. – Felix

+0

DUDE, я думаю, вы, возможно, решили это. У меня было waitUntilDone установлено значение NO. Делает прекрасный смысл: сообщения уведомлений, таблица начинает обновляться, происходит другое уведомление, таблица начинает обновляться во второй раз и сбой! Я буду знать наверняка после следующего обновления, но это имеет смысл, и имеет смысл, что это произошло на 3g, главным образом потому, что это устройство является самым медленным. Я, кстати, с VEVO, поэтому проверьте приложение, если хотите. Еще раз спасибо. ТЫ ЖЖЕШЬ! –

Смежные вопросы