如何在同一方法中将NSURLSession的结果赋给变量?

时间:2014-01-04 05:19:28

标签: objective-c json ios7 nsdictionary nsurlsession

说我是Objective-C的新手将是一个巨大的轻描淡写。我主要是一个Ruby / Rails开发人员,当谈到OOP& amp;编程一般。

在厌倦了阅读教程之后,我决定尝试使用NSRULSession来点击我的一个Rails应用程序(Elder Scrolls Online技能规划师)&在我的iOS应用程序上显示一些JSON响应。代表没有任何意义,我不知道如何将这个功能分解为方法等,所以我认为我会保持简单&在viewDidLoad()方法中完成所有操作(是的,我知道这是不好的做法)。

- (void)viewDidLoad {
    [super viewDidLoad];

    __block NSDictionary *skillData; // No clue what __block is

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:@"http://www.esomix.com/skill_builds/17.json"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSLog(@"%@", json[@"name"]);
        skillData = json;
    }];

    [dataTask resume];

    UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 200, 100)];
    myLabel.textColor = [UIColor colorWithRed:255.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1];
    [self.view addSubview:myLabel];

    NSLog(@"%@", skillData[@"name"]);
    NSLog(@"bottom of method");
}

经过大量的玩弄,我发现尽管我的NSLogs在底部之前有NSURLSession代码,但它们在渲染后会返回它的数据。难怪我的label.text(未显示)没有设定!这是我的三个NSLog的顺序:

(null)
bottom of method
Single-Target Lockdown Sniper

我想我的问题是,在返回数据后,制作JSON API请求并使用数据生成UI元素/其他任务的最简单,正确的方法是什么。非常感谢!

1 个答案:

答案 0 :(得分:3)

一些澄清要点:

  1. 你问

      

    在数据返回后,制作JSON API请求并使用数据生成UI元素/其他任务的最简单,正确的方法是什么

    简而言之,在完成块内使用JSON响应,而不是在它之后,例如:

    - (void)viewDidLoad 
    {
        [super viewDidLoad];
    
        NSURLSession *session = [NSURLSession sharedSession];
        NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:@"http://www.esomix.com/skill_builds/17.json"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    
            NSDictionary *skillData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    
            // use `skillData` here
    
            // finally, any UI/model updates should happen on main queue
    
            dispatch_async(dispatch_get_main_queue(), ^{
                UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 200, 100)];
                myLabel.textColor = [UIColor colorWithRed:255.0/255.0 green:255.0/255.0 blue:255.0/255.0 alpha:1];
                myLabel.text = skillData[@"name"]; // or whatever you wanted from `skillData`
                [self.view addSubview:myLabel];
            });
        }];
    
        [dataTask resume];
    
        // don't try to use `skillData` here, as the above block runs asynchronously,
        // and thus `skillData` will not have been set yet
    }
    
  2. __block限定符的目的是让块更新范围在块之外的变量。但是,因为NSURLSessionDataTask以异步方式运行,所以尝试在该块之外引用skillData是没有意义的(因为viewDidLoad方法将在completionHandler之前完成{如NSURLSessionDataTask结果所示,{1}}会被调用。

    因此,由于在块之外引用NSLog没有意义,因此使用块外的skillData限定符来定义它是没有意义的。只需将其作为块内的局部变量即可。如果要更新模型(或者可能是视图控制器的某些属性),可以这样做(但在处理类属性和ivars时,不需要__block限定符。)