【问题标题】:How to get data from blocks using NSURLSession?如何使用 NSURLSession 从块中获取数据?
【发布时间】:2014-10-03 07:12:13
【问题描述】:

我对这个块有问题。我试图获取NSURLSession 块内的数据。

这是我的代码

-(NSDictionary *) RetrieveData{

    NSURLSession * session = [NSURLSession sharedSession];
    NSURL * url = [NSURL URLWithString: self.getURL];
    dataList =[[NSDictionary alloc] init];

    NSURLSessionDataTask * dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

        self.json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

    }];
    return self.dataList;
    [dataTask resume];

}

是否可以获取NSURLSession的块内的数据?

【问题讨论】:

  • 您是否尝试在块外使用 JSON?该块异步运行,因此您将在执行 JSON 解析的块发生之前早于点击[dataTask resume] 之后的行。
  • 嗨@Rob 我更新了我的帖子。是的,我希望 json 从块中获取数据并在我的方法中返回它。
  • 你没有。如果你想把它传回去,你必须使用完成块模式。
  • 如果我使用这个方法,它仍然返回 null
  • 您不应该从此方法返回任何内容(或者可能只返回 NSURLSessionDataTask 指针)。您在完成块中将数据传回,例如stackoverflow.com/a/26107818/1271826

标签: ios objective-c objective-c-blocks nsurlsession


【解决方案1】:
-(void)getJsonResponse:(NSString *)urlStr success:(void (^)(NSDictionary *responseDict))success failure:(void(^)(NSError* error))failure
{
    NSURLSession *session = [NSURLSession sharedSession];
    NSURL *url = [NSURL URLWithString:urlStr];   

    // Asynchronously API is hit here
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {            
                                                NSLog(@"%@",data);
                                                if (error)
                                                    failure(error);
                                                else {                                               
                                                    NSDictionary *json  = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
                                                    NSLog(@"%@",json);
                                                    success(json);                                               
                                                }
                                            }];
    [dataTask resume];    // Executed First
}

这样称呼:

[self getJsonResponse:@"Enter your url here" success:^(NSDictionary *responseDict) {   
        NSLog(@"%@",responseDict);
    } failure:^(NSError *error) {
        // error handling here ... 
}];

【讨论】:

  • 很高兴我能帮上忙
【解决方案2】:

你应该使用完成块,例如:

- (void)retrieveData:(void (^)(NSDictionary * dictionary))completionHandler {
    NSURLSession *session = [NSURLSession sharedSession];
    NSURL *url = [NSURL URLWithString: self.getURL];

    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];

        if (completionHandler) {
            completionHandler(dictionary);
        }
    }];
    [dataTask resume];
}

然后调用它的方法会这样做:

[self retrieveData:^(NSDictionary *dictionary) {
    // you can use the dictionary here

    // if you want to update UI or model, dispatch this to the main queue:
     dispatch_async(dispatch_get_main_queue(), ^{
         // do your UI stuff here
     });
}];

// but dont try to use the dictionary here, because you will likely
// hit this line before the above block fires off, and thus the 
// dictionary hasn't been returned yet!

您正在调用采用完成块模式的异步方法,因此您还应该在自己的代码中使用完成块模式。

【讨论】:

  • 顺便说一句,注意块使用 local 变量(它作为参数传递给块),而不是实例变量。此外,在风格上,方法总是以小写字母开头,这就是我改变它的原因。
  • 哇!我以为我得到了一个简单的代码。让我先搜索您发布的内容。抱歉,我不熟悉你的代码。
  • 别担心。熟悉该模式需要一段时间。但掌握这一点至关重要,因为您会在 Cocoa API 中到处看到它。每当你看到一个名为“completion”或“completionHandler”的参数时,它总是意味着稍后/异步调用它,如果你想“传回”,它通常需要实现你自己的完成块模式。
  • 我认为熟悉这段代码需要一个月的时间。老实说,我什至不知道什么是 dispatch_async。我将尝试学习和熟悉这一点。无论如何感谢您的帮助。我真的很感激。
  • 是的,当您第一次遇到它时,这可能是一个令人困惑的概念。有时,当您调用具有完成块参数的 API 时,它会在主线程上调用它。对于NSURLSession 方法,它实际上是在后台线程上调用它。但由于所有 UI 代码必须发生在主线程上,dispatch_async 代码表示“该块内的任何内容都将被分派到主线程”。我知道有很多东西需要吸收,但同样,随着您进行越来越多的 Cocoa 编程,它会成为您会非常熟悉的模式。
【解决方案3】:

您必须了解这种方法。最好将您的方法从 RetrieveData(您在此处违反 Cocoa 命名约定)重命名为 startRetrieveData。你不能编写一个真正检索数据的方法,因为在最坏的情况下这可能需要几分钟,而且你的用户会讨厌你。

调用它 startRetrievingData,让它返回 void,并传入两个块,当将来检索到数据时将调用它,当将来发生错误时将调用它,您可以拿不到数据。

您不能返回数据。不要问“我如何返回数据”,你就是不能。您为代码提供一个在数据可用时调用的块,该块 负责处理您想要处理的数据。

【讨论】:

  • 哇!感谢您的意见。对此,我真的非常感激。除了代码,我在这里学到了一些新东西。
【解决方案4】:
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:@"http://www.code-brew.com/projects/Instamigos/api/login.php?instagram_id=572275360&access_token=572275360.4c70214.57e0ecb1113948c2b962646416cc0a18&name=dpak_29&uuid=ios_1"];
// Asynchronously API is hit here
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url
                                        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {    
                                             NSLog(@"%@",data);
                                             // Executed when the response comes from server

                                             // Handle Response here
                                             NSDictionary * json  = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
                                             NSLog(@"%@",json);
}];
[dataTask resume];   // Executed First

【讨论】:

  • 我已经这样做了,但我无法返回json的数据。请看我的更新帖子。如果我使用它,我有一个成功的输出。
  • 你不能从块内返回。你需要另一种方法。我可以使用块为您提供代码
  • 我明白了。请问我该怎么做?
猜你喜欢
  • 1970-01-01
  • 2016-06-05
  • 2015-06-18
  • 2015-07-19
  • 2021-03-09
  • 2015-05-29
  • 2017-05-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多