Не может удовлетворить протоколы (с ассоциированным типом) соответствия - PullRequest
1 голос
/ 26 апреля 2019

Я работаю с CleanSWift в моем новом проекте, и я сталкиваюсь с тем, что это слишком многословно. Чтобы автоматизировать некоторые основные вещи, я написал следующие инструменты (упрощенно):

// MARK: - Presenter

protocol Presenter {
    associatedtype DisplayLogic
    var viewController: DisplayLogic? { get set }
}

protocol PresentationLogic {
    func show(_ error: Error)
}

extension PresentationLogic where Self: Presenter, Self.DisplayLogic: DefaultDisplayLogic {
    func show(_ error: Error) {
    }
}

// MARK: - Display logic

protocol DefaultDisplayLogic: class {
//    func present(_ error: Error)
}

protocol TableViewDisplayLogic: DefaultDisplayLogic {
//    func reloadTableView(with sections: [Section])
}

Когда я пытаюсь реализовать приведенный выше код, обобщения, похоже, не работают. Я получаю сообщение об ошибке «Тип MyPresenter не соответствует протоколу PresentationLogic». Тем не менее, мне кажется, все в порядке.

// MARK: - Controller

protocol MyDisplayLogic: DefaultDisplayLogic {
}

class MyViewController: UIViewController, MyDisplayLogic {
}

// MARK: - Interactor

protocol MyBusinessLogic {
}

class MyInteractor: MyBusinessLogic {
    var presenter: MyPresentationLogic?

    func test() {
        presenter?.show(TestError.unknown)
    }
}

// MARK: - Presenter

protocol MyPresentationLogic: PresentationLogic {
}

class MyPresenter: Presenter, MyPresentationLogic {
    weak var viewController: MyDisplayLogic? // ** Here I get the error. **
}

Есть идеи? Спасибо.

1 Ответ

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

В настоящее время MyPresenter не удовлетворяет требованиям условия where расширения PresentationLogic, поэтому не может использовать реализацию по умолчанию show(_:). В частности, он не проходит тест для Self.DisplayLogic: DefaultDisplayLogic. Следовательно, он не соответствует PresentationLogic, и поэтому он также не соответствует MyPresentationLogic, который наследуется от PresentationLogic.

Но почему бы и нет? Я думаю, это связано с тем, как работает Swift: протоколы не могут соответствовать самим себе. В MyPresenter, Self.DisplayLogic равно MyDisplayLogic. Хотя это дочерний протокол DefaultDisplayLogic, он все еще функционирует как «протокол, пытающийся соответствовать себе», поэтому он не работает.

Чтобы продемонстрировать это, вы можете заменить weak var viewController: MyDisplayLogic? на weak var viewController: MyViewController, и ошибка исчезнет, ​​поскольку это конкретный тип, соответствующий DefaultDisplayLogic. Кроме того, если вы измените Self.DisplayLogic: DefaultDisplayLogic в предложении where на Self.DisplayLogic == MyDisplayLogic, ошибка исчезнет, ​​потому что вам требуется определенный тип, а не соответствие.

В вашем случае возможное решение - сделать MyPresenter универсальным классом. Например:

class MyPresenter<ConcreteDisplayLogic: DefaultDisplayLogic>: Presenter, MyPresentationLogic {
    weak var viewController: ConcreteDisplayLogic?
}

Это позволит вам использовать те же ограничения условия where для реализации по умолчанию show(_:), обеспечивая при этом безопасную для типов обобщенную реализацию MyPresenter.

У этого подхода есть ограничение: вы не можете изменить тип значения viewController для одного экземпляра MyPresenter.

...