无法满足协议(具有关联类型)的一致性

时间:2019-04-26 17:13:50

标签: ios swift generics clean-architecture

我正在与新项目中的CleanSWift一起工作,但我觉得它太罗y了。为了使一些基本的东西自动化,我编写了以下工具(简化了):

// 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 个答案:

答案 0 :(得分:2)

当前,MyPresenter不能满足PresentationLogic扩展的where子句的要求,因此它不能使用show(_:)的默认实现。具体来说,它没有通过Self.DisplayLogic: DefaultDisplayLogic的测试。因此,它不符合PresentationLogic,因此也不符合MyPresentationLogic,后者继承自PresentationLogic

但是为什么不呢?我认为这是由Swift的工作方式引起的:协议无法符合自身要求。在MyPresenter中,Self.DisplayLogicMyDisplayLogic。尽管它是DefaultDisplayLogic的后代协议,但它似乎仍然可以充当“试图符合自身的协议”,因此不起作用。

为证明这一点,您可以将weak var viewController: MyDisplayLogic?替换为weak var viewController: MyViewController,错误将消失,因为它是符合DefaultDisplayLogic的具体类型。另外,如果将where子句中的Self.DisplayLogic: DefaultDisplayLogic更改为Self.DisplayLogic == MyDisplayLogic,则错误将消失,因为您需要的是特定类型而不是一致性。

在您的情况下,可能的解决方案是使MyPresenter成为通用类。例如:

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

这将允许您为show(_:)的默认实现使用相同的where子句约束,同时提供MyPresenter的类型安全的通用实现。

此方法有一个局限性:您无法为viewController的单个实例更改MyPresenter的值的类型。