Неоднозначные функции в нескольких расширениях протокола?
У меня есть несколько протоколов, которые имеют одинаковое имя функции. Некоторые протоколы имеют связанные типы, и я не могу понять, как вызывать функции, как в неуниверсальных протоколах. Я получаю ошибку: Protocol 'MyProtocol1' can only be used as a generic contraint because it has Self or associated type requirements
Вот что я пытаюсь сделать:
protocol Serviceable {
associatedtype DataType
func get(handler: ([DataType] -> Void)?)
}
struct PostService: Serviceable {
func get(handler: ([String] -> Void)? = nil) {
print("Do something...")
}
}
protocol MyProtocol1: class {
associatedtype ServiceType: Serviceable
var service: ServiceType { get }
}
extension MyProtocol1 {
func didLoad(delegate: Self) {
print("MyProtocol1.didLoad()")
}
}
protocol MyProtocol2: class {
}
extension MyProtocol2 {
func didLoad(delegate: MyProtocol2) {
print("MyProtocol2.didLoad()")
}
}
class MyViewController: UIViewController, MyProtocol1, MyProtocol2 {
let service = PostService()
override func viewDidLoad() {
super.viewDidLoad()
didLoad(self as MyProtocol1) // Error here: Protocol 'MyProtocol1' can only be used as a generic contraint because it has Self or associated type requirements
didLoad(self as MyProtocol2)
}
}
Как я могу специально вызвать функцию из общего расширения протокола?
1 ответ
Этого легко достичь, превратив протокол в общий (см. Ниже) или создав ластик типов для этих протоколов, но это очень сильно говорит о том, что у вас есть проблема разработки, и вам следует перепроектировать свои классы и / или расширения. Подобное столкновение убедительно свидетельствует о том, что MyStruct
делает слишком много вещей сам, потому что он тянет в нескольких направлениях MyProtocol1
а также MyProtocol2
, Скорее всего, здесь должно быть два объекта. (Композиция, а не наследство.)
class MyStruct: MyProtocol1, MyProtocol2 {
let service = PostService()
func prot1Load<T: MyProtocol1>(t: T) {
t.didLoad()
}
func prot2Load<T: MyProtocol2>(t: T) {
t.didLoad()
}
init() {
prot1Load(self)
prot2Load(self)
}
}
К вашему конкретному примеру в комментариях я бы использовал композицию, а не наследование. Вы рассматриваете протоколы как множественное наследование, которое почти никогда не бывает правильным. Вместо этого составьте из вещей, которые соответствуют протоколу.
protocol LoadProviding {
func load()
}
struct MyLoader1: LoadProviding {
func load() {
print("MyLoader1.didLoad()")
}
}
struct MyLoader2: LoadProviding {
func load() {
print("MyLoader2.didLoad()")
}
}
protocol Loader {
var loaders: [LoadProviding] { get }
}
extension Loader {
func loadAll() {
for loader in loaders {
loader.load()
}
}
}
class MyStruct: Loader {
let service = PostService()
let loaders: [LoadProviding] = [MyLoader1(), MyLoader2()]
init() {
loadAll()
}
}
Конечно, вы не должны иметь LoadProviding
быть полной структурой. Это может быть просто функция, если это все, что вам нужно:
typealias LoadProviding = () -> Void
func myLoader1() {
print("MyLoader1.didLoad()")
}
func myLoader2() {
print("MyLoader2.didLoad()")
}
protocol Loader {
var loaders: [LoadProviding] { get }
}
extension Loader {
func loadAll() {
for loader in loaders {
loader()
}
}
}
class MyStruct: Loader {
let service = PostService()
let loaders: [LoadProviding] = [myLoader1, myLoader2]
init() {
loadAll()
}
}
Если у вас есть время, чтобы просмотреть видео на эту тему, вас может заинтересовать доклад Beyond Crusty: Real World Protocols от dotSwift. Речь об этом и о похожих проблемах.