面临协议关联类型的问题

时间:2021-04-21 05:00:44

标签: ios swift swift-protocols type-alias

我有一个 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 = ""
}

1 个答案:

答案 0 :(得分:0)

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

因此,您的类型别名:

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(...)))
相关问题