【问题标题】:Facing an issue with protocol associatedType面临协议相关类型的问题
【发布时间】:2021-04-21 05:00:44
【问题描述】:

我有一个 tableview 视图数据列表,用户可以在其中选择一个项目,我使用 ZPPickerDataSource 协议作为数据源,现阶段没有问题

public protocol ZPPickerDataSource: ZPSearchableDataSource {
    var uuID: String {get}
    var displayString: String {get}
}

此外,UI 还具有搜索功能,为此我使用了 ZPSearchableDataSource、ZPSearchable。 ZPPickerDataSource 协议向 ZPSearchableDataSource 确认。

public protocol ZPSearchableDataSource {
    var displayString: String {get}
}

public protocol ZPSearchable {
    associatedtype dataSourceType: ZPSearchableDataSource
    var searchableItems: [dataSourceType] {get}
    func search(keyword: String) -> [dataSourceType]
}

public extension ZPSearchable {
    func search(keyword: String) -> [dataSourceType] {
        return searchableItems.filter{$0.displayString.contains(keyword)}
    }
}

当我提到 ZPSearchable 协议时

typealias dataSourceType = ZPPickerDataSource

我收到类似 您的控制器未确认协议 ZPSearchable 之类的错误。

class MyPickerScreen: ZPSearchable {
    
    typealias dataSourceType = ZPPickerDataSource
    var searchableItems: [dataSourceType] {
        return []
    }
    
    var searchResults: [dataSourceType] = []
    func searchItem(namedLike searchQuery: String) {
        searchResults = search(keyword: searchQuery)
    }
    
}

附注: 我尝试将名为 TestSource 的结构作为数据源。我提到了

typealias dataSourceType = TestSource 

然后代码编译。似乎它只发生在协议中。

public struct TestSource: ZPPickerDataSource {
    public var uuID: String = ""
    public var displayString: String = ""
    public var sampleVar = ""
}

【问题讨论】:

    标签: ios swift swift-protocols type-alias


    【解决方案1】:

    令人惊讶的是,ZPPickerDataSource 不符合 ZPSearchableDataSource。只有具体类型符合协议。协议不符合协议。请参阅 Hamish 在 this post 中的回答了解原因。

    因此,您的类型别名:

    typealias dataSourceType = ZPPickerDataSource
    

    不满足dataSourceType必须符合ZPSearchableDataSource的约束,所以不满足关联类型要求,所以你的类型不符合协议ZPSearchable

    您必须为关联类型使用结构/类。您似乎希望能够使用 any ZPPickerDataSource。在这种情况下,您可以编写一个符合ZPPickerDataSource 的结构,并编写一个将任何ZPPickerDataSource 转换为您的结构的函数:

    struct AnyZPPickerDataSource: ZPPickerDataSource {
        let wrapped: ZPPickerDataSource
        
        var uuID: String { wrapped.uuID }
        var displayString: String { wrapped.displayString }
        
        init(_ dataSource: ZPPickerDataSource) {
            wrapped = dataSource
        }
    }
    

    那么你可以这样做:

    class MyPickerScreen: ZPSearchable {
        var searchableItems: [AnyZPPickerDataSource] = []
        
        typealias dataSourceType = AnyZPPickerDataSource
    }
    

    现在您可以将任何类型的ZPPickerDataSource 放入searchableItems,例如

    searchableItems.append(AnyZPPickerDataSource(TestSource(...)))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多