iPhone - Tableview 中的多线程 - 可行的方法吗?
我最近一直在跟踪一个令人讨厌的错误,我知道它是由于我的多线程方法而发生的(我在最后添加了崩溃报告)。
在我的应用程序中,我加载 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;
}
}
I have been tracking a nasty bug recently of which I knew it was occurring due to my multithreaded approach (I add the crashreport at the end).
In my App I load a UITableView and fill it with data I store using Coredata. This data in turn I retrieve from a webservice, thus it might take some time, depending on my connection.
Anyway, I have managed to track it down a little and I know the issue is because an array is empty though I thought it shouldn't be. Then, when
numberOfRowsInSection:(NSInteger)section
is called the program crashes - but only sometimes!!!
I was wondering how to debug this properly and my approach was to call
reloadData
on the tableView after the view finishes loading. But appearantly
- (void)viewDidLoad
but of course this didn't help. Is the correct way here to create another thread and have it check repeatadly whether the data is ready and prepared? Any suggestions/opinions?
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 looks like:
- (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;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
根据您在此处描述的内容,执行下载的进程(或更准确地说,事件回调)应该是调用重新加载数据的唯一位置。将新数据添加到表数据集后调用它。
在 numberOfRowsInSection 中返回 0 不会导致崩溃,但如果您尝试在计数为 0 时获取嵌套数组,则会崩溃。发布您的
numberOfRowsInSection
方法供我们查看。编辑:
听起来/看起来后台线程在尝试进行对象计数时正在改变数组。
user210504 说得对,同步阵列可能会阻止这种情况。
通常,如果您的后台线程正在改变它,您会同步写入,从而防止
numberOfRowsInSection
进行计数。例如:From what you describe here your process that performs the download, or more precisely an event callback should be the only place calling reload data. calling it after adding new data to the table dataSet.
returning a 0 in numberOfRowsInSection does not cause a crash but if you are trying to get a nested array when the count is 0, this will crash. Post your
numberOfRowsInSection
method for us to gawk at.EDIT:
Sounds/Looks like background thread is mutating the array while its trying to do an object count.
user210504 is right in saying that synchronising the array is likely stop this.
Typically you would sync writes and therefore preventing
numberOfRowsInSection
from counting if your background thread is mutating it. eg:您可以做的一件事是将对可变数组的访问封装在 @synchronized 块中。这样您就可以确保您不会在中途访问数据结构。然后我也同意路加刚才提到的。
One thing that you can do is to encapsulate accesses to the Mutable Array in @synchronized block. This way you will be sure that you are not accessing the datastructure half way through. And then I also agree with what Luke just mentioned.