我有2个功能,可用来在一些网络代码上提供一层。
从历史上看,只有1个函数,但是我只是坐下来扩展它,并意识到除了某些类型之外,它们是相同的。
是否可以使用泛型将它们组合在一起?
那是致命的杀手吗?
我已经阅读了一些书,并且正在努力了解如何在此处实现泛型
func profile(with endpoint: ProfilesEndpoint, method: HTTPMethod, body: String?, headers: [String: String]?, completion: @escaping (Either<ProfileResponse>) -> Void) {
var request = endpoint.request
request.httpMethod = method.rawValue
if let body = body {
request.httpBody = body.data(using: .utf8)
}
if let headers = headers {
for (key, value) in headers {
request.addValue(value, forHTTPHeaderField: key)
}
}
execute(with: request, completion: completion)
}
func identity(with endpoint: IdentityEndpoint, method: HTTPMethod, body: String?, headers: [String: String]?, completion: @escaping (Either<OAuthTokenResponse>) -> Void) {
var request = endpoint.request
request.httpMethod = method.rawValue
if let body = body {
request.httpBody = body.data(using: .utf8)
}
if let headers = headers {
for (key, value) in headers {
request.addValue(value, forHTTPHeaderField: key)
}
}
execute(with: request, completion: completion)
}
我已经尝试过,但是收到一个错误Value of type 'T' has no member 'request'
func request<T: Comparable, X: Comparable>(with endpoint: T, method: HTTPMethod, body: String?, headers: [String: String]?, completion: @escaping (Either<X>) -> Void) {
var request = endpoint.request
request.httpMethod = method.rawValue
if let body = body {
request.httpBody = body.data(using: .utf8)
}
if let headers = headers {
for (key, value) in headers {
request.addValue(value, forHTTPHeaderField: key)
}
}
execute(with: request, completion: completion)
}
答案 0 :(得分:0)
要找到合适的解决方案并不容易,因为这不是我可以直接将粘贴复制到操场上然后玩的东西。无论如何,我希望这会起作用:
protocol Endpoint {
var request: URLRequest { get }
}
extension IdentityEndpoint: Endpoint {}
extension ProfilesEndpoint: Endpoint {}
func genericFunc<T>(with endpoint: Endpoint, method: HTTPMethod, body: String?: headers: [String: String]?, completion: @escaping (Either<T>) -> Void) {
// You can repeat the same stuff here
}
答案 1 :(得分:0)
使用泛型将两个函数替换为一个函数是可能的,也是一个好主意。为此,您首先需要定义一个具有端点通用功能的协议。如果我没看错,它应该看起来像这样:
protocol Endpoint {
associatedtype Response
var request: URLRequest { get }
}
也许您需要向Response
关联类型添加一些约束。这取决于您的execute
函数。
然后,您可以像这样定义通用request
函数:
func request<E: Endpoint>(with endpoint: E, method: HTTPMethod, body: String?, headers: [String: String]?, completion: @escaping (Either<E.Response>) -> Void) { ... }
答案 2 :(得分:0)
您收到该错误,是因为并非所有类型都具有名为request
的变量。泛型不适合这个问题,因为您指的是特定的类(不通用)。
以下两个想法可以解决您的问题:
更改
func request<T: Comparable, X: Comparable>(with endpoint: T, method: HTTPMethod, body: String?, headers: [String: String]?, completion: @escaping (Either<X>) -> Void)
到
private func request(urlRequest: URLRequest, method: HTTPMethod, body: String? , headers: [String: String]?, completion: @escaping (response: HttpResponse) -> Void)
然后从profile(...)
和identity(...)
中调用您的请求函数-
func profile(with endpoint: ProfilesEndpoint, method: HTTPMethod, body: String?, headers: [String: String]?, completion: @escaping (Either<ProfileResponse>) -> Void) {
var urlRequest = endpoint.request
// call request(urlRequest: urlRequest, ...) and handle completion
}
func identity(with endpoint: IdentityEndpoint, method: HTTPMethod, body: String?, headers: [String: String]?, completion: @escaping (Either< OAuthTokenResponse>) -> Void) {
var urlRequest = endpoint.request
// call request(urlRequest: urlRequest, ...) and handle completion
}
private func request(urlRequest: URLRequest, method: HTTPMethod, body: String? , headers: [String: String]?, completion: @escaping (response: HttpResponse) -> Void){
var request = urlRequest
.
.
.
}
创建一个名为Endpoint
的协议,并在ProfileEndpoint和IdentityEndpoint上实现它。
protocol Endpoint{
var request: URLRequest { get }
}
class ProfilesEndpoint: Endpoint {
// this class must contain variable request because it implements Endpoint protocol
var request: URLRequest{
.
.
return ...
}
}
class IdentityEndpoint: Endpoint {
// this class must contain variable request because it implements Endpoint protocol
var request: URLRequest{
.
.
return ...
}
}
然后您可以将请求功能更改为-
(我对Either<>
确实不熟悉,所以不确定您是否会完成)
func request(with endpoint: Endpoint, method: HTTPMethod, body: String?, headers: [String: String]?, completion: @escaping (Either<X>) -> Void) {
var request = endpoint.request
request.httpMethod = method.rawValue
if let body = body {
request.httpBody = body.data(using: .utf8)
}
if let headers = headers {
for (key, value) in headers {
request.addValue(value, forHTTPHeaderField: key)
}
}
execute(with: request, completion: completion)
}
您可以使用IdentityEndpoint
或ProfilesEndpoint
调用此函数,因为它们都符合protocol Endpoint
-声明了变量request
的变量,因此可以肯定的是,这两个类都将具有此变量