在iOS 6上第二次没有设置值。线程问题?

时间:2014-04-12 05:16:20

标签: ios objective-c multithreading networking concurrency

我正在编写一个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:

这是运行线程和调用堆栈的列表。

Call stack

根据我在Android方面的经验,我认为这可能不得不对我做些什么而不是第一次正确完成后台任务,或者某种方式应该在后台任务之后运行的代码与它一起运行第二次。

如果有任何建议可以帮助我解决这个问题,我将不胜感激!

由于

1 个答案:

答案 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,以避免此类问题。