2014-04-12 69 views
0

我在寫一個iOS應用程序,該應用程序使用從服務器檢索到的數據填充數組,並將其顯示在選取器視圖中。iOS 6上的第二次設置值。線程問題?

第一次顯示視圖時一切順利;但是,切換到另一個使用相機掃描內容並使用滑出菜單(使用SWRevealViewController構建)切換回的視圖時,它無法填充陣列。當我們在後臺任務完成檢索記錄後在UI線程上訪問它時,會出現NSRangeException錯誤index 0 beyond bounds for empty array

我很肯定後臺任務正在運行,數據正在成功檢索,因爲我將每個請求記錄到服務器。

我認爲這可能是一個併發問題,後臺線程不更新變量。

據我們測試,這個問題只出現在iOS 6中,並沒有發生,或至少目前還沒有,在iOS 7

這是用來檢索和設置的代碼陣列:

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]; 
    }); 
}); 

這是我的SidebarViewController方法prepareforSegue是負責當從滑出菜單選擇的項目視圖之間的切換。

- (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]; 
     }; 
    } 
} 

視圖從故事板鏈接在一起切換。

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { 

    // Set the current id 
    _currentId = [NSString stringWithFormat:@"%d", row]; 
    _currentName = [[_events objectAtIndex:row] objectForKey:@"event_name"]; 
      -----------^ 
... 

這裏是正在運行的線程和調用堆棧列表:

的錯誤,當我嘗試檢索從我events陣列中的pickerView:didSelectRow:inComponent:方法的特定條目發生。

Call stack

從我的Android體驗,我認爲這可能必須做一些事情跟我沒有完成後臺任務正確地在第一時間,或以某種方式是應該的後臺任務後運行的代碼,是第二次與它一起運行。

我希望任何建議,可能會幫助我解決這個問題!

由於

回答

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,爲了避免這樣的問題。

+0

感謝您的回答。它解決了問題!我猜測它必須在線程之間進行變量鎖定和同步,但我不確定如何解決它。 –