我正在编写一个利用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];
}
答案 0 :(得分: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];
});
});
虽然基于回调的API(如NSURLConnection
)可能最适合网络加载,但这样做效果会相当不错。特别是对于小额请求。