Я создаю некоторый класс, подтверждающий общий протокол, этот общий протокол имеет метод, который принимает параметр типа associatedtype
, я использую Xcode для создания заглушки для меня:
import UIKit
struct SomeObject: Codable {
var id: String?
var name: String?
}
protocol INetworkManager {
associatedtype ResponseObject
func get(url: String, ofType: ResponseObject.Type, completion: (ResponseObject?, Error?) -> Void)
}
class NetworkManager: INetworkManager {
typealias ResponseObject = Codable
func get(url: String, ofType: ResponseObject.Protocol, completion: (ResponseObject?, Error?) -> Void) {
completion(SomeObject(id: "1", name: "hello"), nil)
}
}
Вместо ResponseObject.Type
он генерирует ResponseObject.Protocol
для меня, я на самом деле не знаю, что это за ResponseObject.Protocol
, и я не могу передать SomeObject.self
в качестве параметра следующим образом:
let networkManager = NetworkManager()
networkManager.get(url: "http://whatever.com", ofType: SomeObject.self) { (responseObject, error) in
print("got response object named: \(responseObject.name)")
}
компилятор выдал мне эту ошибку:
error: Cannot convert value of type 'SomeObject.Type' to expected argument type 'NetworkManager.ResponseObject.Protocol' (aka '(Decodable & Encodable).Protocol')
Я думаю, что что-то не так с моей реализацией, кто-нибудь может дать мне какие-либо идеи?
Спасибо!
Чего вы пытаетесь достичь? Когда у вас есть associatedtype
на protocol
, то нет необходимости передавать его в качестве аргумента функции. Вы можете напрямую использовать MyType.self
в методе.
@JeremyP Извините за мою ошибку, приведенный выше фрагмент кода теперь исправлен.
@Kamaran На самом деле, я хочу написать общий протокол для своего NetworkManager
, в котором метод get
принимает класс Codable
. Я обновил приведенный выше фрагмент, чтобы показать, чего я хочу достичь, пожалуйста, посмотрите, спасибо.
Передача типов в Swift — это плохой запах. Вам почти никогда не нужно это делать. Переосмыслите это.
@matt Мне нужен метод get
, чтобы вернуть объект этого Type
, и этот Type
различается в разных конечных точках API, что мне делать, кроме передачи типов?
Это не то, как работают ассоциированные типы. get
должен быть универсальным для своего типа ответа, но сам сетевой менеджер не является универсальным для определенного типа ответа. Я считаю, что вы имели в виду вот это:
protocol NetworkManager {
func get<ResponseObject>(url: String,
ofType: ResponseObject.Type,
completion: (Result<ResponseObject, Error>) -> Void)
where ResponseObject: Decodable
}
class TrivialNetworkManager: NetworkManager {
func get<ResponseObject>(url: String,
ofType: ResponseObject.Type,
completion: (Result<ResponseObject, Error>) -> Void)
where ResponseObject: Decodable {
completion(.success(SomeObject(id: "1", name: "hello"))
}
}
Для более подробной версии этой конкретной проблемы вы можете прочитать мой серия протоколов, но важная концепция здесь заключается в том, что NetworkManager не зависит от своего ResponseType, поэтому нет причин делать его ResponseType ассоциированным типом.
То, что вы написали, пытается сказать: «Некоторые сетевые менеджеры будут иметь Codable ResponseType, а другие сетевые менеджеры будут иметь какой-то другой тип ResponseType». Не «какой-то другой конкретный тип ответа (например, User)», а «какой-то другой протокол, которому должны соответствовать его типы ответов». Хотя создать что-то подобное можно, это гораздо сложнее, и вам нужно будет объяснить свой конкретный вариант использования, чтобы спроектировать его. В частности, вам нужно будет показать несколько конкретных реализаций вашего протокола, чтобы увидеть, какой общий код вы пытаетесь извлечь.
Привет, Роб, спасибо за подробный ответ! Я должен был пропустить использование associatedtype
, которое означало, что оно может быть разным для разных конкретных классов, и не для этого случая использования. Я изменю свой код, чтобы вместо этого использовать общий метод в протоколе.
Пожалуйста, не могли бы вы исправить MCVE. Ваш класс не соответствует протоколу.