2016-04-25 2 views
1

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

Как я могу специально вызвать функцию от расширения общего протокола?

ответ

2

Этого просто достичь, превратив протокол в общий (см. Ниже), или создав для этих протоколов type eraser, но это очень сильно говорит о том, что у вас есть проблемы с дизайном, и вы должны пересмотреть свои классы и/или расширения , Такое столкновение говорит о том, что 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. Речь идет об этой и подобных проблемах.

+0

Действительно пахнет. Я пытаюсь добиться множественного наследования с использованием расширений протокола. Например, в 'viewDidLoad' моего' UIViewController', я хотел бы выполнить каждую функцию 'didLoad' каждого из моих протоколов. – TruMan1

+0

Тогда у вас должно быть свойство типа 'let loader: [Loader]', который содержит различные инициализации, которые вам нужны. –

+0

Я, вероятно, подумал бы более глубоко об именах здесь, чтобы они соответствовали текущим стилям стиля Swift, но выше все равно, как я, безусловно, на него напал. –

Смежные вопросы