我的应用使用JSON解析来自Rails应用的信息。我正在寻找一种异步加载JSON的方法,但由于代码的复杂性,我无法让我的代码使用我找到的示例。我需要做什么才能异步加载JSON?感谢。
- (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];
}
答案 0 :(得分:7)
一种简单的方法是使用NSURLConnection
方便的类方法sendAsynchronousRequest:queue:error
。
以下代码片段是一个如何从服务器加载JSON的示例,以及完成处理程序在解析JSON的后台线程上执行的示例。它还执行所有建议的错误检查:
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这是一种简约而又天真的方法。除其他缺点外,主要问题是:
更复杂的方法需要使用NSURLConnection
代理。通常,第三方库以这种方式实现它,将NSURLConnection
请求和其他相关状态信息封装到NSOperation
的子类中。您可以从自己的实现开始,例如使用this code作为模板。
答案 1 :(得分:1)
如果你只想获得这个json数据,你不需要设置很多东西。
使用以下代码。创建获取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];
});
});
答案 2 :(得分:0)
按照以下答案下载您的数据异步:Object-c/iOS :How to use ASynchronous to get a data from URL?
然后通过json解析器运行它。
答案 3 :(得分:0)
要在后台线程中一般运行代码,您可以使用此方法:
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元素。此外,它们不允许您从后台线程生成更多线程,它必须从主线程完成。
答案 4 :(得分:0)
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];
}
}];
答案 5 :(得分:-1)
试试这段代码:
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"];
}];