Неоднозначные функции в нескольких расширениях протокола?

У меня есть несколько протоколов, которые имеют одинаковое имя функции. Некоторые протоколы имеют связанные типы, и я не могу понять, как вызывать функции, как в неуниверсальных протоколах. Я получаю ошибку: 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. Речь об этом и о похожих проблемах.

Другие вопросы по тегам