在单独的静态方法中访问 NSURLSessionTasks 的委托 class

Accessing delegate of NSURLSessionTasks wrapped in static method in separate class

我为我的应用编写了一个单独的 Web 服务 class - WebServices.m。

其中,我有几个静态方法,如setUserInput()、getUserProfile()、registerNewUser()、logOutofAccount()。在这些方法中,我包含了各种 NSURLRequests 和 NSURLSession 任务,它们成功地到达了我服务器的端点。

我可以轻松地在各种 ViewController 中调用这些静态方法 - 我只是做 [WebServices registerNewUser]。问题是,现在我想做以下事情:

  1. 从任务中访问响应项
  2. 任务完成后转到新的Viewcontroller

我一直在使用每个 completionHandler: 中的完成块,但我假设我想做的是,我需要改用委托?如果是这样,

示例将不胜感激,因为我对这一切还很陌生,而且我在 Whosebug 上找不到任何相关内容。

谢谢!

编辑:

WebServices.m 中带有完成处理程序的静态方法示例。

+(void)logOutAccount{
// 1
NSURL *url = [NSURL URLWithString:@"https://mywebsite.com/logout/"];
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.HTTPAdditionalHeaders = @{@"Authorization": @"Token 123456678809203490249019203"};
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig];

// 2
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
request.HTTPMethod = @"POST";

// 3
NSDictionary *dictionary = @{};
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary
                                               options:kNilOptions error:&error];

if(!error){
    NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
                                                               fromData:data completionHandler:^(NSData *data,NSURLResponse *response,NSError *error) {
                                                                   // Handle response here
                                                                   NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
                                                                   NSLog(@"%i",httpResponse.statusCode);
                                                               }];

    // 5
    [uploadTask resume];
}
}

在 ViewController.m viewDidLoad() 中,我只是调用 [WebServices logOutAccount]。但是如何访问 completionHandler 的 NSURLResponse 呢?我应该使用代表吗?这就是为什么我在上面问我的问题:)

  1. 完成块

URL Session Programming Guide所述

Note: Completion callbacks are primarily intended as an alternative to using a custom delegate. If you create a task using a method that takes a completion callback, the delegate methods for response and data delivery are not called.

因此,在您的情况下使用完成块是可以的,但是,

问题 #1: 您的代码不会将回调传递给调用者(例如 ViewController)。

在您的网络服务中 header:

typedef void (^WebServicesCompletionHandler)(id responseObject, NSError *error);

+ (void)logOutAccountWithCompletionHandler:(WebServicesCompletionHandler)completionBlock;

这个方法,他们都能用

问题 #2: 您使用 NSURLSessionUploadTask 作为 API(注销),不应将任何数据上传到服务器。同样,我不知道您的服务器 API,但我宁愿使用 NSURLSessionDataTask 来处理此 API。

NSURLSessionDataTask* dataTask =
[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data,
                                                         NSURLResponse * _Nullable response,
                                                         NSError * _Nullable error) {
    // process response, data and error
}
[dataTask resume];

问题 #3: 您的代码实际上并没有回调

// if the result from the API is processed from the UI, pass them in main queue
dispatch_async_main(^{
    // make sure the caller has passed completionBlock
    if (completionBlock) {
        completionBlock(responseObject, error);
    }
});

因此,完整的方法如下所示:

+ (void)logOutAccountWithCompletionHandler:(WebServicesCompletionHandler)completionBlock {

    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    sessionConfig.HTTPAdditionalHeaders = @{@"Authorization": @"Token 123456678809203490249019203"};
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig];

    NSURL *url = [NSURL URLWithString:@"https://mywebsite.com/logout/"];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    request.HTTPMethod = @"POST";

    NSURLSessionDataTask* dataTask =
    [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data,
                                                         NSURLResponse * _Nullable response,
                                                         NSError * _Nullable error) {
        dispatch_async_main(^{
            // make sure the caller has passed completionBlock
            if (completionBlock) {
                completionBlock(response, error);
            }
        });
    }];

    [dataTask resume];
}

您可以从 ViewController

使用它
WebServicesCompletionHandler completionHandler;
completionHandler = ^(id response, NSError* error) {
    if (error == nil) {
        // process a response object
    }
    else {
        // process an error
    }
};
[WebServices logOutAccountWithCompletionHandler: completionHandler];
  1. 代表

使用委托涉及到更多的事情要做,所以最好找到一个完整的例子,而不是post这里。现在,我认为您可以尝试完成块解决方案。让我知道。

P.S.: 我建议您阅读一些教程以更加熟悉网络通信(例如 this one