我正在实施自定义NSURLProtocol
,并且内部希望将NSURLSession
用于内部网络的数据任务,而不是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加载系统向上传递某些身份验证问题,我需要使用NSURLSession
客户端方法:
- (void)URLProtocol:(NSURLProtocol *)protocol didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
我的问题是completionHandler
和NSURLAuthenticationChallenge.client
的内部实现是否相同,如果是这样,我是否可以跳过调用委托方法中的完成处理程序,期望URL加载系统会调用相应的NSURLAuthenticationChallenge.client
方法吗?
答案 0 :(得分:6)
要回答我自己的问题,答案是否定的。此外,Apple提供的挑战发送者没有实现整个NSURLAuthenticationChallengeSender
协议,因此当客户端尝试响应挑战时崩溃:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFURLSessionConnection performDefaultHandlingForAuthenticationChallenge:]: unrecognized selector sent to instance 0x7ff06d958410'
我的解决方案是创建一个包装器:
@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
我使用我的包装发件人替换挑战对象:
NSURLAuthenticationChallenge* challengeWrapper = [[NSURLAuthenticationChallenge alloc] initWithAuthenticationChallenge:challenge sender:[[CPURLSessionChallengeSender alloc] initWithSessionCompletionHandler:completionHandler]];
[self.client URLProtocol:self didReceiveAuthenticationChallenge:challengeWrapper];