ios - 如何从 NSURLSessionDataTask 完成处理程序返回 NSData

标签 ios objective-c ios7 nsurlsession

我正在尝试制作一个简单的类,我可以用它来调用 post web 服务。

除了我无法返回 NSData 之外,一切正常。

这是我的代码:

+ (NSData *)postCall:(NSDictionary *)parameters fromURL:(NSString *)url{
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
    NSMutableArray *pairs = [[NSMutableArray alloc]init];
    for(NSString *key in parameters){
        [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, parameters[key]]];
    }
    NSString *requestParameters = [pairs componentsJoinedByString:@"$"];
    NSURL *nsurl = [NSURL URLWithString:url];
    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:nsurl];
    [urlRequest setHTTPMethod:@"POST"];
    [urlRequest setHTTPBody:[requestParameters dataUsingEncoding:NSUTF8StringEncoding]];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        //return data;
    }];
    [dataTask resume];

    return nil;
}

请注意我有 //return data 但它给了我这个错误

 Incompatible block pointer types sending 'NSData *(^)(NSData *__strong, NSURLResponse *__strong, NSError *__strong)' to parameter of type 'void (^)(NSData *__strong, NSURLResponse *__strong, NSError *__strong)'

我的问题是:

  1. 我的方法好还是会给我带来麻烦?我没有要下载的图像,也没有要上传的任何内容,我只需要发送简单的字符串数据并接收简单的字符串数据。还是最好在每个函数中独立编写代码?

  2. 请问如何返回数据?

最佳答案

你不能只返回数据(因为 NSURLSessionDataTask 异步运行)。您可能希望使用自己的完成 block 模式,类似于 dataTaskWithRequest 方法的 completionHandler

因此,您可以将自己的 block 参数添加到您的方法中,您将从 dataTaskWithRequest 方法的 completionHandler 内部调用:

+ (NSURLSessionDataTask *)postCall:(NSDictionary *)parameters fromURL:(NSString *)url completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler {

    // create your request here ...

    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (completionHandler)
            completionHandler(data, response, error);
    }];

    [dataTask resume];

    return dataTask;
}

或者,因为这个 dataTaskWithRequest 在后台线程上运行,所以有时确保将完成处理程序分派(dispatch)回主队列很有用,例如

NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if (completionHandler)
        dispatch_async(dispatch_get_main_queue(), ^{
            completionHandler(data, response, error);
        });
}];

请注意,顺便说一句,我认为返回 NSURLSessionDataTask 引用是很好的,就像上面那样,这样 (a) 调用者可以确保数据任务已成功创建; (b) 你有 NSURLSessionTask 引用,你可以使用它来取消任务,以防在未来的某个日期,你希望能够出于某种原因取消请求(例如,用户取消了发出请求的 View Controller )。

无论如何,您可以通过以下方式调用它:

NSURLSessionTask *task = [MyClass postCall:parameters fromURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    // put whatever code you want to perform when the asynchronous data task completes
}];

if (!task) {
    // handle failure to create task any way you want
}

你问:

Is my way good or it will cause me problems in the future? I don't have [an] image to download and I don't have anything to upload, I just have to send [some] simple string data and receive [simple] string data. Or it will be better to but that code in each function independently?

如果您收到简单的字符串数据,我建议您以 JSON 格式编写响应,然后在 postCall 中使用 NSJSONSerialization 完成 block 来提取响应。使用 JSON 让应用程序更容易区分成功的响应和各种可能也返回字符串响应的服务器相关问题。

因此,假设您修改了服务器代码以返回如下响应:

{"response":"some text"}

然后您可以修改 postCall 来解析该响应,如下所示:

+ (NSURLSessionDataTask *)postCall:(NSDictionary *)parameters fromURL:(NSString *)url completionHandler:(void (^)(NSString *responseString, NSError *error))completionHandler {

    // create your request here ...

    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (completionHandler) {
            if (error) {
                completionHandler(nil, error);
            } else {
                NSError *parseError = nil;
                NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&parseError];

                completionHandler(responseDictionary[@"response"], parseError);
            }
        }
    }];

    [dataTask resume];

    return dataTask;
}

就您的基本问题而言,postCall 这样的方法是否有意义,是的,我认为将创建请求的细节放在一个方法中是非常有意义的。我对你的实现的小保留是你决定使它成为一个类方法而不是一个实例方法。您目前正在为每个请求创建一个新的 NSURLSession。我建议将 postCall 设为实例方法(如果需要,可以是单例),然后将 session 保存为类属性,设置一次,然后在后续查询中重复使用。

关于ios - 如何从 NSURLSessionDataTask 完成处理程序返回 NSData,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24851772/

相关文章:

java - InetAddress.getAllByName() 抛出 UnknownHostException

ios - HTTP 请求 header

c++ - Box2d - 在彼此之上产生 body

ios - 在 iOS 7 中更改条形按钮的颜色

ios - 应用商店拒绝: ASIdentifierManager

ios - UIGraphicsBeginImageContextWithOptions 和多线程

ios - 如何在考虑特殊字符的情况下选择字段中的文本?

ios - 在后端验证 ios 开发者帐户

ios - 与名为 com.apple.nsurlstorage-cache 的服务的连接已失效

ios - 动画 UIButton 状态淡入淡出点击