ios - 访问包装在单独类中的静态方法中的 NSURLSessionTasks 的委托(delegate)

标签 ios objective-c nsurlconnection nsurlsession

我为我的应用程序编写了一个单独的 WebServices 类 - WebServices.m。

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

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

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

我一直在使用每个 completionHandler: 中的完成 block ,但我假设我正在尝试做的事情,我需要改用委托(delegate)?如果是这样,

  • 如果我在其他类中使用静态方法,如何访问委托(delegate)?
  • 每个委托(delegate)如何区分调用它们的不同任务?

非常感谢示例,因为我对这一切都很陌生,并且在 StackOverflow 上找不到任何相关内容。

谢谢!

编辑:

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.

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

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

在您的 Web 服务的 header 中:

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

+ (void)logOutAccountWithCompletionHandler:(WebServicesCompletionHandler)completionBlock;

这个方法,他们可以用

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

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. 代表

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

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

关于ios - 访问包装在单独类中的静态方法中的 NSURLSessionTasks 的委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35060971/

相关文章:

ios - View 不显示和自动布局集中

ios - 微信SDK集成iOS

ios - 带有 sendAsynchronousRequest Objective-C 的 NSURLConnection 进度条

objective-c - NSURLRequest/NSURLConnection ios 5.0 v/s 早期版本

iphone - 使用 NSURLConnection 和 NSURLProtectionSpace 确定信任

ios - AVplayer 无法播放 iPhone 画廊中的视频

ios - NSLogs 中的 unsigned int 和 unsigned long Xcode 警告

ios - Realm +地幔: how to avoid multiple inheritance duplication when integrating both frameworks?

iOS 电子邮件地址验证不接受 .in

ios - ionic 5 电容器 : Push Notification with ONESIGNAL not working on iOS