0

如果说我是 Objective-C 的新手,那就太轻描淡写了。我主要是一名 Ruby/Rails 开发人员,当谈到 OOP 和一般编程时,它完全宠坏了我。

在厌倦了阅读教程之后,我决定尝试使用 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");
}

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

(null)
bottom of method
Single-Target Lockdown Sniper

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

4

1 回答 1

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在该块之外引用是没有意义的(因为该方法将在调用for theviewDidLoad之前完成,如您的结果所示)。completionHandlerNSURLSessionDataTaskNSLog

    所以,既然在块外引用没有意义,那么在块外用限定符skillData定义它就没有意义了。__block只需将其设置为块内的局部变量即可。如果您想更新您的模型(或者可能是视图控制器的某些属性),您可以这样做(但是在处理类属性和 ivars 时,不需要__block限定符)。

于 2014-01-04T06:38:51.663 回答