0

我正在编写一个利用 UITabBarController 切换视图的应用程序。在填充 UITableView 之前,一个选项卡发出 Web 请求以收集并处理 JSON 数据。我正在尝试在后台加载此数据,因此当用户按下选项卡时,呈现表格不会延迟。将显示一个 ActivityIndi​​cator,然后在表格中加载数据。

每个请求都被提出、处理并将结果放置在一个 NSMutableArray 中,然后对其进行排序并添加到 UITableView。

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

所以,我的问题是什么是允许用户切换到包含此 TableView 的选项卡的正确模式,在数据加载和处理(在后台)时呈现一个 ActivityIndi​​cator,然后一旦完成,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];

}
4

1 回答 1

0

Dispatch_sync()实际上会阻塞调用它的线程,因为它会停止执行以将块排队。Dispatch_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];
    });
});

虽然像这样的基于回调的 APINSURLConnection可能最适合网络加载,但这会很好地工作。特别是对于小请求。

于 2012-02-14T02:48:56.407 回答