【问题标题】:Can't use property of a protocol type once protocol has associated type [duplicate]一旦协议具有关联类型,就无法使用协议类型的属性[重复]
【发布时间】:2021-09-29 07:05:25
【问题描述】:

我已经开始创建一个基础存储库类,它将保存每个数据模型的数据,但我也希望它尽可能通用。 我还需要协议来通知这个存储库的消费者关于 in 的变化。想法是也有通用的数据更改机制,而不是根据数据类型定义 20 个协议。代码如下所示:

protocol BaseRepositoryDelegate {
    associatedtype dataType
    func didUpdateData(allData: [dataType], currentPage: [dataType], totalDataCount: Int, tag: Int?)
    func didGetError(error: ApiError)
}

class BaseRepository<T> {
    typealias dataType = T
    var delegate: BaseRepositoryDelegate?
    var tag: Int?

    private(set) public var data = [T]()
    private(set) public var currentPage = 0
    private(set) public var totalCount = 0

    init(delegate: BaseRepositoryDelegate, tag: Int? = nil) {
        self.delegate = delegate
        self.tag = tag
    }
}

我遇到的问题是 delegate 属性会导致错误提示 Protocol 'BaseRepositoryDelegate' can only be used as a generic constraint because it has Self or associated type requirements 并且我无法解决该问题并保留存储库类和基本协议的通用功能。关于如何解决这个问题的任何想法?

我的最终目标是拥有一个 SpecificRepository 类,它可以继承 BaseRepository 并以某种方式提供可以为 Protocol 和 BaseRepository 定义 dataType 的参数。

class SpecificRepository: BaseRepository<MySpecificType> {
    typealias dataType = MySpecificType

    // I can override methods here or properties based 
    // on my use-case, or I can add specific functionality.
}

【问题讨论】:

    标签: ios swift repository-pattern


    【解决方案1】:

    如错误消息所示,改为将其设为泛型类型。此外 typealias 声明是没有意义的,因为您不使用它并且它与协议没有任何联系。将 T 与协议的关联类型连接,再见,在类声明中添加 where 条件(我还将 T 重命名为 DataType)

    class BaseRepository<DataType, Delegate: BaseRepositoryDelegate> where Delegate.dataType == DataType{
        typealias dataType = DataType
        var delegate: Delegate?
        var tag: Int?
    
        private(set) public var data = [DataType]()
        private(set) public var currentPage = 0
        private(set) public var totalCount = 0
    
        init(delegate: Delegate, tag: Int? = nil) {
            self.delegate = delegate
            self.tag = tag
        }
    }
    

    简单示例

    struct RepoDelegate: BaseRepositoryDelegate {
        typealias dataType = Int
    
        func didUpdateData(allData: [Int], currentPage: [Int], totalDataCount: Int, tag: Int?) {}
        func didGetError(error: ApiError) {}
    }
    
    let delegate = RepoDelegate()
    let repo = BaseRepository(delegate: delegate, tag: nil)
    

    要将其用于子类,您需要定义要扩展基类的数据类型和委托类型

    SpecificRepository: BaseRepository<MySpecificType, SpecificRepoDelegate>
    

    我们匹配委托的类型

    struct SpecificRepoDelegate: BaseRepositoryDelegate {
        typealias dataType = MySpecificType
        //...
    }
    

    【讨论】:

    • 这是一个很好的例子,谢谢 Joakim!我的最终用例与您提供的有点不同,所以让我试着解释一下我想要实现的目标(问题已更新)。
    • @Aleksandar 回答已更新
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-27
    • 1970-01-01
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多