如何asynchronous加载JSON(iOS)

我的应用程序使用JSONparsing来自Rails应用程序的信息。 我正在寻找一种asynchronous加载JSON的方式,但是由于我的代码的复杂性,我无法让我的代码与我find的示例一起工作。 我需要做什么来使我的JSON加载asynchronous? 谢谢。

- (void)viewDidLoad { [super viewDidLoad]; NSURL *upcomingReleaseURL = [NSURL URLWithString:@"http://obscure-lake-7450.herokuapp.com/upcoming.json"]; NSData *jsonData = [NSData dataWithContentsOfURL:upcomingReleaseURL]; NSError *error = nil; NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error]; NSArray *upcomingReleasesArray = [dataDictionary objectForKey:@"upcoming_releases"]; //This is the dateFormatter we'll need to parse the release dates NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; NSTimeZone *est = [NSTimeZone timeZoneWithAbbreviation:@"EST"]; [dateFormatter setTimeZone:est]; [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]]; //A bit of an overkill to avoid bugs on different locales //Temp array where we'll store the unsorted bucket dates NSMutableArray *unsortedReleaseWeek = [[NSMutableArray alloc] init]; NSMutableDictionary *tmpDict = [[NSMutableDictionary alloc] init]; for (NSDictionary *upcomingReleaseDictionary in upcomingReleasesArray) { //We find the release date from the string NSDate *releaseDate = [dateFormatter dateFromString:[upcomingReleaseDictionary objectForKey:@"release_date"]]; //We create a new date that ignores everything that is not the actual day (ignoring stuff like the time of the day) NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *components = [gregorian components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:releaseDate]; //This will represent our releases "bucket" NSDate *bucket = [gregorian dateFromComponents:components]; //We get the existing objects in the bucket and update it with the latest addition NSMutableArray *releasesInBucket = [tmpDict objectForKey:bucket]; if (!releasesInBucket){ releasesInBucket = [NSMutableArray array]; [unsortedReleaseWeek addObject:bucket]; } UpcomingRelease *upcomingRelease = [UpcomingRelease upcomingReleaseWithName:[upcomingReleaseDictionary objectForKey:@"release_name"]]; upcomingRelease.release_date = [upcomingReleaseDictionary objectForKey:@"release_date"]; upcomingRelease.release_price = [upcomingReleaseDictionary objectForKey:@"release_price"]; upcomingRelease.release_colorway = [upcomingReleaseDictionary objectForKey:@"release_colorway"]; upcomingRelease.release_date = [upcomingReleaseDictionary objectForKey:@"release_date"]; upcomingRelease.thumb = [upcomingReleaseDictionary valueForKeyPath:@"thumb"]; upcomingRelease.images = [upcomingReleaseDictionary objectForKey:@"images"]; [releasesInBucket addObject:upcomingRelease]; [tmpDict setObject:releasesInBucket forKey:bucket]; } [unsortedReleaseWeek sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { NSDate* date1 = obj1; NSDate* date2 = obj2; //This will sort the dates in ascending order (earlier dates first) return [date1 compare:date2]; //Use [date2 compare:date1] if you want an descending order }]; self.releaseWeekDictionary = [NSDictionary dictionaryWithDictionary:tmpDict]; self.releaseWeek = [NSArray arrayWithArray:unsortedReleaseWeek]; } 

一个简单的方法是使用NSURLConnection的方便的类方法sendAsynchronousRequest:queue:error

以下代码片段是如何从服务器加载JSON以及完成处理程序在parsingJSON的后台线程上执行的示例。 它还执行所有build议的错误检查:

 NSURL* url = [NSURL URLWithString:@"http://example.com"]; NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL:url]; [urlRequest addValue:@"application/json" forHTTPHeaderField:@"Accept"]; NSOperationQueue* queue = [[NSOperationQueue alloc] init]; [NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse* response, NSData* data, NSError* error) { if (data) { NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; // check status code and possibly MIME type (which shall start with "application/json"): NSRange range = [response.MIMEType rangeOfString:@"application/json"]; if (httpResponse.statusCode == 200 /* OK */ && range.length != 0) { NSError* error; id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; if (jsonObject) { dispatch_async(dispatch_get_main_queue(), ^{ // self.model = jsonObject; NSLog(@"jsonObject: %@", jsonObject); }); } else { dispatch_async(dispatch_get_main_queue(), ^{ //[self handleError:error]; NSLog(@"ERROR: %@", error); }); } } else { // status code indicates error, or didn't receive type of data requested NSString* desc = [[NSString alloc] initWithFormat:@"HTTP Request failed with status code: %d (%@)", (int)(httpResponse.statusCode), [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode]]; NSError* error = [NSError errorWithDomain:@"HTTP Request" code:-1000 userInfo:@{NSLocalizedDescriptionKey: desc}]; dispatch_async(dispatch_get_main_queue(), ^{ //[self handleError:error]; // execute on main thread! NSLog(@"ERROR: %@", error); }); } } else { // request failed - error contains info about the failure dispatch_async(dispatch_get_main_queue(), ^{ //[self handleError:error]; // execute on main thread! NSLog(@"ERROR: %@", error); }); } }]; 

虽然看起来有些复杂,但IMO却是一个简约而又天真的方法。 除其他缺点之外,主要问题是:

  • 它缺乏取消请求的可能性
  • 没有办法处理更复杂的authentication。

更复杂的方法需要使用NSURLConnection 委托 。 通常,第三方库通过这种方式实现它,将NSURLConnection请求和其他相关状态信息封装到NSOperation的子类中。 您可以从自己的实现开始,例如使用此代码作为模板。

如果你只想得到这个只有json数据,你不需要设置很多东西。

使用下面的代码。 创build获取NSData对象的jsonParse方法。

  dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul); dispatch_async(queue, ^{ NSData *data = [[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:@"http://obscure-lake-7450.herokuapp.com/upcoming.json"]]; dispatch_sync(dispatch_get_main_queue(), ^{ [self jsonParse:data]; }); }); 

像这个答案一样下载asynchronous数据: Object-c / iOS:如何使用asynchronous从URL获取数据?

然后通过jsonparsing器运行它。

要在后台线程中通用运行代码,可以使用以下方法:

 dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Code here is run on a background thread dispatch_async( dispatch_get_main_queue(), ^{ // Code here is run on the main thread (the UI thread) after your code above has completed so you can update UI after the JSON call has completed if you need to. }); }); 

但请记住,Apple不允许您在后台线程中更新UI元素。 而且,它们不允许你从后台线程产生更多的线程,它必须从主线程完成。

 NSString *urlstr=@"http://itunes.apple.com/in/rss/topsongs/limit=25/json"; NSMutableURLRequest *request=[[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:urlstr]]; [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse* response, NSData* data, NSError* error) { NSError *myError = nil; NSDictionary *dic1 = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&myError]; if (myError ==nil) { NSDictionary*feed =[dic1 objectForKey:@"feed"]; NSArray*arrayofentry =[feed objectForKey:@"entry"]; for(NSDictionary *dic2 in arrayofentry) { requestReply=[dic2 objectForKey:@"title"]; [arr1 addObject:requestReply]; } [self.table reloadData]; } }]; 

试试这个代码:

  NSURL * inkURL = [NSURL URLWithString:@"your url"]; NSURLRequest * request = [[NSURLRequest alloc]initWithURL:inkURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0]; NSOperationQueue * queue = [[NSOperationQueue alloc]init]; [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse * response, NSData * data, NSError * error) { NSData * jsonData = [NSData dataWithContentsOfURL:inkURL]; NSDictionary * dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error]; self.inkArray = [dataDictionary objectForKey:@"users"]; }];