Objective c 在UITabViewController中使用dispatch_sync检索数据

Objective c 在UITabViewController中使用dispatch_sync检索数据,objective-c,xcode,uitableview,grand-central-dispatch,uitabview,Objective C,Xcode,Uitableview,Grand Central Dispatch,Uitabview,我正在编写一个应用程序,它利用UITabBarController切换视图。一个选项卡在填充UITableView之前发出web请求以收集并处理JSON数据。我试图在后台加载这些数据,这样当用户按下选项卡时,就不会延迟显示表格。将显示一个ActivityIndicator,然后该表将加载数据 每个请求都会发出、处理并将结果放入NSMutableArray中,然后将其排序并添加到UITableView中 当我使用dispatch_sync时,数据被加载,数组被创建并显示良好,但是视图的UI被阻止加

我正在编写一个应用程序,它利用UITabBarController切换视图。一个选项卡在填充UITableView之前发出web请求以收集并处理JSON数据。我试图在后台加载这些数据,这样当用户按下选项卡时,就不会延迟显示表格。将显示一个ActivityIndicator,然后该表将加载数据

每个请求都会发出、处理并将结果放入NSMutableArray中,然后将其排序并添加到UITableView中

当我使用dispatch_sync时,数据被加载,数组被创建并显示良好,但是视图的UI被阻止加载。我这样想是因为出于某种原因,我没有将此查询发送到后台队列。如果使用dispatch_async,则在尝试访问主线程上的NSMutableArray时会出现异常

因此,我的问题是,允许用户切换到包含此TableView的选项卡,在加载和处理数据(在后台)时显示ActivityIndicator,然后在完成后,使用处理后的数据加载UITableView的正确模式是什么

UITableViewController中的相关代码:

#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

- (void)viewDidLoad
{
    [super viewDidLoad];

    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

    currentLat = appDelegate.currentLatitude;
    currentLong = appDelegate.currentLongitude;

    finalDistanceArray = [[NSMutableArray alloc] init];

    [self compareLocationMMC];
    [self compareLocationLVMC];
    [self compareLocationSBCH];
    [self compareLocationGVCH];
    [self compareLocationSYVCH];

    NSSortDescriptor *lowestToHighest = [NSSortDescriptor sortDescriptorWithKey:@"distance" ascending:YES];

    [hospitalList sortUsingDescriptors:[NSArray arrayWithObject:lowestToHighest]];  

}

- (void)compareLocationMMC {


NSString * searchURL = [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/directions/json?origin=%f,%f&destination=%f,%f&sensor=true", currentLat.floatValue, currentLong.floatValue, MMC_LAT, MMC_LON];
NSURL * myURL = [NSURL URLWithString:searchURL];

dispatch_sync(kBgQueue, ^{
    NSData* data = [NSData dataWithContentsOfURL: 
                    myURL];
     [self performSelectorOnMainThread:@selector(fetchedData:) 
                          withObject:data waitUntilDone:YES];
});


}
//The compareLocationXXX method is repeated 4 more times with different search strings

- (void)fetchedData:(NSData *)responseData {

//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization 
                      JSONObjectWithData:responseData 

                      options:kNilOptions 
                      error:&error];

NSArray* stationDistance = [json objectForKey:@"routes"]; 

NSDictionary* legs = [stationDistance objectAtIndex:0];

NSArray* legsBetween = [legs objectForKey:@"legs"];

NSDictionary* distanceBetween = [legsBetween objectAtIndex:0];

finalDistance = [distanceBetween valueForKeyPath:@"distance.text"];

[finalDistanceArray addObject:finalDistance];

}
Dispatch\u sync()
实际上会阻止从中调用它的线程,因为它会停止执行以使块排队
Dispatch\u async
是一个更好的选择,因为它允许继续调用函数。您可以将一个调用封装在另一个调用中,以允许您在主线程上执行完成代码。这也使得代码的执行非常容易阅读

// Turn on status bar spinner, for example
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    // Do background stuff here
        ....
    NSData* data = [NSData dataWithContentsOfURL:myURL];
    // used parsed data to populate data structure of some type
        ....
    dispatch_async(dispatch_get_main_queue(), ^{
        // Use background stuff here
        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
    });
});

虽然像
NSURLConnection
这样的基于回调的API可能最适合网络加载,但这将非常有效。特别是对于小请求。

谢谢!我相信我在后台可以很好地工作,但是随后的代码访问NSMutableArray,并在加载数据之前访问它,从而导致异常。在访问数据之前,我应该如何等待以确保数据已加载和排序?在“在此处使用背景资料”部分之前,您不应该使用加载的数据。这可能会复制您获取的数据并调用
reloadTable