К вашему актуальному вопросу, тип ластика прост:
final class AnyClient<T: EndpointType>: ClientType {
let _request: (T) -> Void
func request(_ request: T) { _request(request) }
init<Client: ClientType>(_ client: Client) where Client.T == T {
_request = client.request
}
}
Вам понадобится одна из этих _func/func
пар для каждого требования в протоколе. Вы можете использовать это так:
let client = AnyClient(Client<ProfilesAPI>())
И тогда вы можете создать тестовый жгут, как:
class RecordingClient<T: EndpointType>: ClientType {
var requests: [T] = []
func request(_ request: T) -> Void {
requests.append(request)
print("recording: \(request.baseURL)")
}
}
И используйте это вместо:
let client = AnyClient(RecordingClient<ProfilesAPI>())
Но я не очень рекомендую этот подход, если вы можете избежать его. Тип ластики являются головной болью. Вместо этого я бы заглянул внутрь Client
и выделил неуниверсальную часть в протокол ClientEngine
, который не требует T
. Затем сделайте , что может быть заменен при создании Client
. Тогда вам не нужны ластики типов, и вам не нужно предоставлять дополнительный протокол для вызывающих (просто EndpointType).
Например, часть двигателя:
protocol ClientEngine: class {
func request(_ request: String) -> Void
}
class StandardClientEngine: ClientEngine {
func request(_ request: String) -> Void {
print(request)
}
}
Клиент, который держит двигатель. Обратите внимание, как он использует параметр по умолчанию, чтобы вызывающим абонентам не приходилось ничего менять.
class Client<T: EndpointType> {
let engine: ClientEngine
init(engine: ClientEngine = StandardClientEngine()) { self.engine = engine }
func request(_ request: T) -> Void {
engine.request(request.baseURL)
}
}
let client = Client<ProfilesAPI>()
И снова версия записи:
class RecordingClientEngine: ClientEngine {
var requests: [String] = []
func request(_ request: String) -> Void {
requests.append(request)
print("recording: \(request)")
}
}
let client = Client<ProfilesAPI>(engine: RecordingClientEngine())