Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 如何将依赖性传递给URLProtocol子类?_Ios_Swift_Dependency Injection_Urlsession_Nsurlprotocol - Fatal编程技术网

Ios 如何将依赖性传递给URLProtocol子类?

Ios 如何将依赖性传递给URLProtocol子类?,ios,swift,dependency-injection,urlsession,nsurlprotocol,Ios,Swift,Dependency Injection,Urlsession,Nsurlprotocol,我一直在开发一个拦截器,用于在我的应用程序中向网络请求添加身份验证头 final类AuthInterceptor:URLProtocol{ 私有var令牌:String=“my.access.token” 私有var数据任务:URLSessionTask? 私有结构意外值PresentationError:错误{} 重写类func canInit(带有请求:URLRequest)->Bool{ 属性(forKey:“is_handled”,in:request)为?Bool==nil else{

我一直在开发一个拦截器,用于在我的应用程序中向网络请求添加身份验证头

final类AuthInterceptor:URLProtocol{
私有var令牌:String=“my.access.token”
私有var数据任务:URLSessionTask?
私有结构意外值PresentationError:错误{}
重写类func canInit(带有请求:URLRequest)->Bool{
属性(forKey:“is_handled”,in:request)为?Bool==nil else{return false}
返回真值
//return false//URL加载系统将使用系统的默认行为处理请求
}
重写类func canonicalRequest(对于请求:URLRequest)->URLRequest{
退货申请
}
覆盖函数加载(){
guard let mutableRequest=(请求为NSURLRequest).mutableCopy()为?NSMutableURLRequest else{return}
setProperty(true,forKey:“已处理”,in:mutableRequest)
mutableRequest.addValue(令牌,forHTTPHeaderField:“授权”)
dataTask=URLSession.shared.dataTask(其中:mutableRequest作为URLRequest){[weak self]数据,响应,错误
guard let self=self-else{return}
如果let error=error{
self.client?.urlProtocol(self,didFailWithError:error)
}否则,如果let data=data,则let response=response{
self.client?.urlProtocol(self,didLoad:data)
self.client?.urlProtocol(self,didcreceive:response,cacheStoragePolicy:.不允许)
}否则{
self.client?.urlProtocol(self,didFailWithError:UnexpectedValuesRepresentationError())
}
self.client?.urlprotocoldFinishLoading(self)
}
dataTask?.resume()
}
重写函数停止加载(){
数据任务?.cancel()
dataTask=nil
}
}
正如您所看到的,我目前正在使用
private-var-token:String=“my.access.token”
模拟令牌。我想介绍一个
TokenLoader
,它将从缓存中获取我的令牌

由于URL加载系统将根据需要初始化我的协议实例,我不确定如何注入它。它当前使用以下方式注册:
URLProtocol.registerClass(AuthInterceptor.self)

想象一下,我有一个这样的界面-

公共类型别名LoadTokenResult=Result 公共协议令牌加载器{ func load(ukey:String,completion:@escaping(LoadTokenResult)->Void) } 我想确保这是可测试的,所以我希望能够在测试用例中存根或使用间谍


如何实现这一点?

一个可能的选择是为此使用泛型

protocol TokenProvider {
    static var token: String {get}
}

class MockTokenProvider: TokenProvider {
    static var token: String = "my.access.token"
}
并将AuthInterceptor更改为:

    final class AuthInterceptor<T: TokenProvider>: URLProtocol {
      private var token: String = T.token
    ....
    ...
}
URLProtocol.registerClass(AuthInterceptor<MockTokenProvider>.self)
final类AuthInterceptor:URLProtocol{
私有变量令牌:String=T.token
....
...
}
并登记如下:

    final class AuthInterceptor<T: TokenProvider>: URLProtocol {
      private var token: String = T.token
    ....
    ...
}
URLProtocol.registerClass(AuthInterceptor<MockTokenProvider>.self)
URLProtocol.registerClass(AuthInterceptor.self)

上面的代码是在操场上编译的,但没有在实际项目中尝试过。

正如所见,
AuthInterceptor
不依赖于实例级别的
TokenProvider
,因此您可以注入类级依赖项,并使用共享的
TokenProvider
来提取/加载令牌(例如,取决于URL)。这使得注入缓存令牌提供程序以方便测试成为可能

final class AuthInterceptor: URLProtocol {

    static var tokenProvider: TokenLoader?  // << inject here

    // initial value, will be loaded from to tokenProvider result
    private var token: String?  

    // ... other code
    
    // somewhere inside when needed, like
    Self.tokenProvider?.load(key) { [weak self] result in
       self?.token = try? result.get()

       // proceed with token if present ...
    }
}

你曾经成功过吗?这无疑增加了可测试性。但就我个人而言,我更感兴趣的是问题的“传递依赖性”部分。我希望能够传递一个类的实例,以便能够获取我的访问令牌。也许这还需要另一个问题。