Reputation: 39
I have this protocol:
protocol PostDataProviderProtocol{
var delegate:DataProviderDelegate? { get set }
func fetchData<T>(url:String, onload: @escaping ([T?], CustomErrorStruct?) -> Void)
func load(onload:@escaping(Bool, CustomErrorStruct?,PostDataProviderProtocol?) -> Void)
func load(onload:@escaping(Bool, CustomErrorStruct?,PostDataProviderProtocol?) -> Void, force:Bool)
func reload(onload:@escaping(Bool, CustomErrorStruct?,PostDataProviderProtocol?) -> Void)
func hasNext() ->Bool
func getItemAt<T>(index:Int)-> T?
func getOffset() -> Int
func setEndpoint(endpoint: String)
func getEndpoint() -> String
func setItemsPerPage(itemsPerPage: Int)
func getItemsPerPage() -> Int
func setPage(page: Int)
func getPage() -> Int
func getLength() -> Int
func composeEndpointUrl()-> String
func composeEndpointUrl(offset:Int?, limit:Int?)-> String
func getItems<T>() -> [T]
func replaceItemAt<T>(index:Int, item:T?)
func removeItemAt(index:Int)
}
I have a class implementing this protocol with an extension, like this:
class BaseDataProvider<T> {
internal var _itemsPerPage:Int
internal var _page:Int
internal var _endpoint:String
internal var cachedData:[T?]
}
extension BaseDataProvider: PostDataProviderProtocol{
func getItems<T>() -> [T] {
return self.cachedData as! [T]
}
func replaceItemAt<T>(index: Int, item: T?){
self.cachedData.append(item)
}
}
As you can see, the cacheData
type is an generic array.
The problem is in the line
self.cachedData.append(item)
The compiler throws this error:
Cannot convert value of type 'T?' to expected argument type 'T?'
Completed code without base protocol for T
:
import Foundation
protocol DataProviderProtocol{
func getItemAt<T>(index:Int)-> T?
func getItems<T>() -> [T?]
func replaceItemAt<T>(index:Int, item:T?)
func removeItemAt(index:Int)
}
class BaseDataSource<T> {
internal var cachedData:[T?] = []
}
extension BaseDataSource: DataProviderProtocol{
func getItemAt<T>(index: Int) -> T? {
return self.cachedData[index]
}
func getItems<T>() -> [T?] {
return self.cachedData
}
func replaceItemAt<T>(index: Int, item: T?) {
return self.cachedData[index] = item
}
func removeItemAt(index: Int) {
self.cachedData.remove(at: index)
}
}
With base protocol for T
Type
import Foundation
protocol DataProviderProtocol{
func getItemAt<T>(index:Int)-> T?
func getItems<T>() -> [T?]
func replaceItemAt<T>(index:Int, item:T?)
func removeItemAt(index:Int)
}
class BaseTypeForT{
}
class BaseDataSource<T:BaseTypeForT>{
internal var cachedData:[T?] = []
}
extension BaseDataSource: DataProviderProtocol{
func getItemAt<T>(index: Int) -> T? {
return self.cachedData[index]
}
func getItems<T>() -> [T?] {
return self.cachedData
}
func replaceItemAt<T>(index: Int, item: T?) {
return self.cachedData[index] = item
}
func removeItemAt(index: Int) {
self.cachedData.remove(at: index)
}
}
How can I solve this?
Upvotes: 0
Views: 2924
Reputation: 51882
You need to use an associatedtype
in your protocol so all functions/variables in the protocol uses the same type because otherwise each function with a <T>
will be using a different type
Example (simplified
protocol PostDataProviderProtocol{
associatedtype T
func getItemAt(index:Int)-> T?
func replaceItemAt(index:Int, item:T?)
}
Then in your class you can use it as
class BaseDataProvider<SomeType> {
internal var _itemsPerPage:Int = 0
internal var _page:Int = 0
internal var _endpoint:String = ""
internal var cachedData:[SomeType?] = []
}
extension BaseDataProvider: PostDataProviderProtocol {
typealias T = SomeType
func hasNext() -> Bool {
true
}
func getItemAt(index: Int) -> T? {
self.cachedData[index]
}
func getItems() -> [T] {
return self.cachedData as! [T]
}
}
Upvotes: 3