繁体   English   中英

如何异步加载JSON(iOS)

[英]How to load JSON asynchronously (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];

}

一种简单的方法是使用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的子类中。 您可以从自己的实现开始,例如使用此代码作为模板。

如果你只想获得这个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];

    });
});

按照以下答案下载您的数据异步: Object-c / iOS:如何使用ASynchronous从URL获取数据?

然后通过json解析器运行它。

要在后台线程中一般运行代码,您可以使用此方法:

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"];


        }];

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM