我正在编写一个iOS应用程序,使用从服务器检索到的数据填充数组,并将其显示在选择器视图中。
第一次显示视图时,一切顺利;但是,当切换到使用相机扫描内容并使用滑出菜单(使用SWRevealViewController构建)切换回来的另一个视图时,它无法填充数组。当我们在后台任务完成检索记录后在UI线程上访问它时,会引发错误NSRangeException
的{{1}}。
我非常确定正在运行后台任务,并且在将每个请求记录到服务器时成功检索数据。
我认为这可能是并发问题和后台线程没有更新变量的问题。
据我们测试,此问题仅出现在iOS 6上,并且在iOS 7上不会发生,或者至少还没有发生。
这是用于检索和设置数组的代码:
index 0 beyond bounds for empty array
这是我的dispatch_queue_t queue = dispatch_queue_create("com.aaa.bbb", NULL);
dispatch_async(queue, ^{
_events = [_wi getEvents:_auth_token];
dispatch_async(dispatch_get_main_queue(), ^{
// code to be executed on the main thread when background task is finished
[_mPicker reloadComponent:0];
// Set the default on first row
[self pickerView:_mPicker didSelectRow:0 inComponent:0];
[pDialog dismissWithClickedButtonIndex:0 animated:YES];
});
});
中的prepareforSegue
方法,负责在从幻灯片菜单中选择项目时切换视图。
SidebarViewController
视图从故事板链接在一起以便切换。
当我尝试使用- (void) prepareForSegue: (UIStoryboardSegue *) segue sender: (id) sender
{
// Set the title of navigation bar by using the menu items
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *destViewController = (UINavigationController*)segue.destinationViewController;
destViewController.title = [[_menuItems objectAtIndex:indexPath.row] capitalizedString];
if ( [segue isKindOfClass: [SWRevealViewControllerSegue class]] ) {
SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;
swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {
UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
[navController setViewControllers: @[dvc] animated: NO ];
[self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
};
}
}
方法从events
数组中检索特定条目时发生错误:
pickerView:didSelectRow:inComponent:
这是运行线程和调用堆栈的列表。
根据我在Android方面的经验,我认为这可能不得不对我做些什么而不是第一次正确完成后台任务,或者某种方式应该在后台任务之后运行的代码与它一起运行第二次。
如果有任何建议可以帮助我解决这个问题,我将不胜感激!
由于
答案 0 :(得分:1)
从不同的线程访问变量_events
,没有任何同步机制。
试试这个:
dispatch_queue_t queue = dispatch_queue_create("com.aaa.bbb", NULL);
dispatch_async(queue, ^{
NSArray* events = [_wi getEvents:_auth_token];
dispatch_async(dispatch_get_main_queue(), ^{
_events = [events copy];
// code to be executed on the main thread when background task is finished
[_mPicker reloadComponent:0];
// Set the default on first row
[self pickerView:_mPicker didSelectRow:0 inComponent:0];
[pDialog dismissWithClickedButtonIndex:0 animated:YES];
});
});
同样_events
应该是NSArray
,而不是NSMutableArray
,以避免此类问题。