1 Вопрос: Swift5. Расширение протокола вызывает ошибку компиляции «Невозможно вызвать функцию со списком аргументов типа Self»

вопрос создан в Tue, Apr 9, 2019 12:00 AM

Я хотел бы реализовать какой-то шаблон Decorator, который позволяет писать повторно используемые декораторы

Итак, я определил 2 протокола. Первый определяет тип для декоратора:

    protocol ViewDecorator {
        associatedtype View: Decoratable
        func decorate(view: View)
    }

    // this is how I expect to use decorator
    class GreenViewDecorator: ViewDecorator {
        typealias View = GreenView

        func decorate(view: GreenView) {
            view.backgroundColor = UIColor.green
        }
    }

Второй определяет тип, которому decoratable должен соответствовать вид.

    protocol Decoratable {
        func decorate<T: ViewDecorator>(with decorator: T)
    }

    extension Decoratable where Self: UIView {
        func decorate<T : ViewDecorator>(with decorator: T) {
            decorator.decorate(view: self)
        }
    }

    // exampled of 'decoratable' view
    class GreenView: UIView, Decoratable { }

Я определил реализацию по умолчанию функции func decorate<T : ViewDecorator>(with decorator: T) в расширении протокола. Я вижу, это полезно, если мой взгляд будет реализовывать метод по умолчанию. Мне просто нужно только наследовать протокол Decoratable. И тогда я могу использовать это как:

    // example of using decorator with view
    let decorator = GreenViewDecorator()
    greenView.decorate(with: decorator)

Но компилятор Swift5 выдает ошибку в строке decorator.decorate(view: self)

  

Невозможно вызвать 'decorate' со списком аргументов типа '(view: Self)'

 Ошибка компиляции

============== TOTAL LISTING ==========
    protocol ViewDecorator {
        associatedtype View: Decoratable
        func decorate(view: View)
    }

    protocol Decoratable {
        func decorate<T: ViewDecorator>(with decorator: T)
    }

    extension Decoratable where Self: UIView {
        func decorate<T : ViewDecorator>(with decorator: T) {
            decorator.decorate(view: self)
        }
    }

    class GreenView: UIView, Decoratable { }

    class GreenViewDecorator: ViewDecorator {
        typealias View = GreenView

        func decorate(view: GreenView) {
            view.backgroundColor = UIColor.green
        }
    }

    class ViewController: UIViewController {
        @IBOutlet var greenView: GreenView!

        override func viewDidLoad() {
            super.viewDidLoad()
            let decorator = GreenViewDecorator()
            greenView.decorate(with: decorator)
        }
    }
    
0
1 ответ                              1                         

Тип аргумента - это связанный тип View, но нигде не установлено, что Self является этим типом, поэтому вы не можете передать аргумент типа Self, не установив его совместимость. Например:

extension Decoratable where Self: UIView {
    func decorate<T: ViewDecorator>(with decorator: T) where T.View == Self {
        decorator.decorate(view: self)
    }
}

(Однако, если вы это сделаете, у вас возникнут проблемы с соответствием протоколу Decoratable, так как он требует этот метод для любого ViewDecorator. Можно также изменить протокол, чтобы иметь такое же ограничение T.View == Self.) р>     

2
2019-04-09 11: 32: 30Z
  1. Спасибо. Это работает. protocol Decoratable { func decorate<T: ViewDecorator>(with decorator: T) where T.View == Self }
    2019-04-09 11: 40: 21Z
источник размещен Вот