NSURLSessionTaskauthentication挑战completionHandler和NSURLAuthenticationChallenge客户端

我正在实现一个自定义NSURLProtocol ,并在内部想要使用NSURLSession数据任务的内部networking,而不是NSURLConnection

我碰到了一个有趣的问题,并想知道NSURLSession / NSURLSessionTask的质询处理程序的内部实现。

 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler; 

在这里,我基本上提供了两个不同的挑战处理程序,一个是completionHandler块,它提供了处理挑战的所有必要的信息,但是也有传统的NSURLAuthenticationChallenge.client ,它具有几乎与一对一对应的方法completionHandler信息选项。

由于我正在开发一个协议,并且想要向调用API实现的URL加载系统向上传递一定的authentication挑战,我需要使用NSURLSession客户端方法:

 - (void)URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; 

我的问题是completionHandlerNSURLAuthenticationChallenge.client的内部实现是否相同,如果是这样,我可以跳过在委托方法中调用完成处理程序,期望URL加载系统将调用适当的NSURLAuthenticationChallenge.client方法吗?

回答我自己的问题,答案是否定的。 此外,苹果公司提供的挑战发件人不实施整个NSURLAuthenticationChallengeSender协议,从而在客户端尝试应对挑战时崩溃:

 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFURLSessionConnection performDefaultHandlingForAuthenticationChallenge:]: unrecognized selector sent to instance 0x7ff06d958410' 

我的解决scheme是创build一个包装:

 @interface CPURLSessionChallengeSender : NSObject <NSURLAuthenticationChallengeSender> - (instancetype)initWithSessionCompletionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler; @end @implementation CPURLSessionChallengeSender { void (^_sessionCompletionHandler)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential); } - (instancetype)initWithSessionCompletionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { self = [super init]; if(self) { _sessionCompletionHandler = [completionHandler copy]; } return self; } - (void)useCredential:(NSURLCredential *)credential forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { _sessionCompletionHandler(NSURLSessionAuthChallengeUseCredential, credential); } - (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { _sessionCompletionHandler(NSURLSessionAuthChallengeUseCredential, nil); } - (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; { _sessionCompletionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); } - (void)performDefaultHandlingForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { _sessionCompletionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); } - (void)rejectProtectionSpaceAndContinueWithChallenge:(NSURLAuthenticationChallenge *)challenge { _sessionCompletionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil); } @end 

我用新包装的发件人replace了挑战对象:

 NSURLAuthenticationChallenge* challengeWrapper = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:challenge sender:[[CPURLSessionChallengeSender alloc] initWithSessionCompletionHandler:completionHandler]]; [self.client URLProtocol:self didReceiveAuthenticationChallenge:challengeWrapper];