3

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

}
4

6 回答 6

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. 您可以从自己的实现开始,例如使用此代码作为模板。

于 2013-10-09T08:01:46.100 回答
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];

    });
});
于 2013-10-09T06:13:28.217 回答
0

按照以下答案异步下载您的数据:Object-c/iOS :How to use ASynchronous to get a data from URL?

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

于 2013-10-09T00:54:17.810 回答
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 元素。此外,它们不允许您从后台线程生成更多线程,必须从主线程中完成。

于 2013-10-09T06:21:34.440 回答
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];
    }
}];
于 2015-04-30T14:59:28.647 回答
-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"];


        }];
于 2014-03-12T07:31:58.930 回答