如何异步加载JSON(iOS)

Chr*_*oya 3 json ios

我的应用程序使用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];

}
Run Code Online (Sandbox Code Playgroud)

Cou*_*per 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);
        });
    }
}];
Run Code Online (Sandbox Code Playgroud)

尽管看起来有些复杂,但IMO仍然是一种简约而又天真的方法.除其他缺点外,主要问题是:

  • 它缺乏取消请求的可能性,并且
  • 没有办法处理更复杂的身份验证.

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