Swift5. Расширение протокола вызывает ошибку компиляции «Невозможно вызвать функцию со списком аргументов типа Self» - PullRequest
0 голосов
/ 09 апреля 2019

Я хотел бы реализовать какой-нибудь шаблон 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' со списком аргументовtype '(view: Self)'

Compilation error

============== 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)
        }
    }

1 Ответ

2 голосов
/ 09 апреля 2019

Тип аргумента - это связанный тип 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.

...