简体   繁体   中英

Facing an issue with protocol associatedType

I have a list of tableview view data where user can pick one item i'm using ZPPickerDataSource protocol as a datasource, there is no issue at this stage

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

In addition the UI has search funcitonality as well, i'm using ZPSearchableDataSource, ZPSearchable for that. ZPPickerDataSource protocol confirms to 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)}
    }
}

when i mentions ZPSearchable protocol's

typealias dataSourceType = ZPPickerDataSource

i'm getting an error like Your controller does not confirms to protocol ZPSearchable .

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

PS: I've tried struct named TestSource as a data source. and i mentioned

typealias dataSourceType = TestSource 

then the code compiles. seems it occurs only with protocol.

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

Surprisingly, ZPPickerDataSource does not conform to ZPSearchableDataSource . Only concrete types conform to protocols. Protocols do not conform to protocols. See Hamish's answer in this post for why.

Because of this, your type alias:

typealias dataSourceType = ZPPickerDataSource

does not satisfy the constraint that dataSourceType must conform to ZPSearchableDataSource , so the associated type requirement is not met, so your type does not conform to the protocol ZPSearchable .

You must use a struct/class for the associated type. You seem to want to be able to use any ZPPickerDataSource . In that case, you can write a struct that conforms to ZPPickerDataSource , and write a function that converts from any ZPPickerDataSource to your struct:

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

Then you can do:

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

Now you can put any kind of ZPPickerDataSource into searchableItems , eg

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM