iPhone - многопоточность в Tableview - возможный подход - PullRequest
1 голос
/ 20 января 2011

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

В моем приложении я загружаю UITableView и заполняю его данными, которые храню с помощью Coredata. Эти данные, в свою очередь, я получаю из веб-сервиса, поэтому это может занять некоторое время, в зависимости от моего соединения.

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

numberOfRowsInSection:(NSInteger)section

называется сбой программы - но только иногда !!!

Мне было интересно, как отладить это правильно, и мой подход был вызвать

reloadData

в tableView после завершения загрузки представления. Но, по-видимому,

- (void)viewDidLoad 

но, конечно, это не помогло. Правильный ли здесь способ создания другого потока и повторной проверки, готовы ли данные и подготовлены? Любые предложения / мнения?

2011-01-19 21:50:49.605 myApp[2017:307] *** Terminating app due to uncaught exception         
'NSRangeException', reason: '*** -[NSMutableArray objectAtIndex:]: index 0 beyond bounds for empty array'
*** Call stack at first throw:
(
0   CoreFoundation                      0x314d0987 __exceptionPreprocess + 114
1   libobjc.A.dylib                     0x319a149d objc_exception_throw + 24
2   CoreFoundation                      0x31462795 -[__NSArrayM objectAtIndex:] + 184 
3   myApp                                 0x000092f7 -[MyTableViewController tableView:numberOfRowsInSection:] + 106
4   UIKit                               0x33902bcf -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 1338
5   UIKit                               0x33903529 -[UITableViewRowData(UITableViewRowDataPrivate) _ensureSectionOffsetIsValidForSection:] + 120
6   UIKit                               0x33902645 -[UITableViewRowData numberOfRows] + 96
7   UIKit                               0x3390207b -[UITableView noteNumberOfRowsChanged] + 82
8   UIKit                               0x33901bff -[UITableView reloadData] + 582
9   UIKit                               0x33904a0b -[UITableView _reloadDataIfNeeded] + 50
10  UIKit                               0x33904e63 -[UITableView layoutSubviews] + 18
11  UIKit                               0x338b10cf -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 26
12  CoreFoundation                      0x3146ebbf -[NSObject(NSObject) performSelector:withObject:] + 22
13  QuartzCore                          0x30a6c685 -[CALayer layoutSublayers] + 120
14  QuartzCore                          0x30a6c43d CALayerLayoutIfNeeded + 184
15  QuartzCore                          0x30a6656d _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 212
16  QuartzCore                          0x30a66383 _ZN2CA11Transaction6commitEv + 190
17  QuartzCore                          0x30a70e4f _ZN2CA11Transaction5flushEv + 46
18  QuartzCore                          0x30a6db75 +[CATransaction flush] + 24
19  UIKit                               0x338e803f -[UIApplication _reportAppLaunchFinished] + 30
20  UIKit                               0x338d6317 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 462
21  UIKit                               0x338a248b -[UIApplication handleEvent:withNewEvent:] + 1114
22  UIKit                               0x338a1ec9 -[UIApplication sendEvent:] + 44
23  UIKit                               0x338a1907 _UIApplicationHandleEvent + 5090
24  GraphicsServices                    0x35d66f03 PurpleEventCallback + 666
25  CoreFoundation                      0x314656ff __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 26
26  CoreFoundation                      0x314656c3 __CFRunLoopDoSource1 + 166
27  CoreFoundation                      0x31457f7d __CFRunLoopRun + 520
28  CoreFoundation                      0x31457c87 CFRunLoopRunSpecific + 230
29  CoreFoundation                      0x31457b8f CFRunLoopRunInMode + 58
30  UIKit                               0x338d5309 -[UIApplication _run] + 380
31  UIKit                               0x338d2e93 UIApplicationMain + 670
32  myApp                               0x000029bf main + 70
33  myApp                               0x00002974 start + 40
)
terminate called after throwing an instance of 'NSException'

numberOfRows выглядит так:

- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
NSLog(@"number of rows in section");
if (section == mySection) {

    return  [[articleArrays objectAtIndex:section] count];  

} else {
    return 0;
}
* *} Тысяча двадцать-один

Ответы [ 2 ]

1 голос
/ 20 января 2011

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

, возвращающий 0 в numberOfRowsInSection, не приводит к сбою, но если вы пытаетесь получить вложенный массив, когда число равно 0, это приведет к сбою.Опубликуйте ваш numberOfRowsInSection метод для нас, чтобы поглазеть.

РЕДАКТИРОВАТЬ:

Звучит / Похоже, что фоновый поток изменяет массив при попытке выполнить подсчет объектов.

user210504 прав, говоря, что синхронизация массива, скорее всего, остановит это.

Обычно вы синхронизируете записи и, следовательно, не допускаете подсчета numberOfRowsInSection, если ваш фоновый поток изменяет его.например:

-(void)downloadFinished{

NSMutableArray * array  = [[NSArray alloc] init];//t
id * obj;//obj is your row data object.

@synchronized(ar)
{
    [array addObject:obj];//ar is your dataSet
}

[array release];
}
0 голосов
/ 20 января 2011

Одна вещь, которую вы можете сделать, это инкапсулировать доступ к Mutable Array в блок @synchronized. Таким образом, вы будете уверены, что не получите доступ к структуре данных на полпути. И тогда я также согласен с тем, что только что упомянул Люк.

...