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

// 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. **
}

有任何想法吗?谢谢。

最佳答案

当前,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子句约束,同时提供typet安全,通用的MyPresenter实现。

这种方法有一个局限性:您不能为viewController的单个实例更改MyPresenter值的类型。

10-08 15:41