I have a data model where product can change based on the experimentation (AB Testing), so I have a struct with generics
struct DataModel<T: Sendable & Equatable> {
var product: T?
// there are other properties,
}
I have data provider and a protocol
protocol SomeProtocol: AnyObject {
func fetchedData<T: Sendable & Equatable>(data: [DataModel<T>])
}
class DataProvider {
weak var delegate: SomeProtocol?
func getData() {
//this is a async flow for simplicity am adding synchronous code here
var someObjects = [DataModel<SKProduct>]()
delegate?.fetchedData(data: someObjects)
}
}
Finally a UIViewController
class SomeViewController<T: Sendable & Equatable>: UIViewController {
func renderUI(data: [DataModel<T>]) {
debugPrint(data)
}
}
extension SomeViewController: SomeProtocol {
func fetchedData<T>(data: [DataModel<T>]) {
renderUI(data: data)
}
}
But I am getting the following error at line renderUI(data: data)
Cannot convert value of type '[SomeRandomProject.DataModel<T>]' to expected argument type '[SomeRandomProject.DataModel<T>]'
EDIT 1:
Following @Sulthan's answer below I modified my code to
protocol SomeProtocol: AnyObject {
associatedtype DataType: Sendable & Equatable
func fetchedData(data: [DataModel<DataType>])
}
class DataProvider {
weak var delegate: (any SomeProtocol)?
func getData() {
var someObjects = [DataModel<SKProduct>]()
delegate?.fetchedData(data: someObjects)
}
}
class SomeViewController<T: Sendable & Equatable>: UIViewController, SomeProtocol {
typealias DataType = T
func fetchedData(data: [DataModel<T>]) {
renderUI(data: data)
}
func renderUI(data: [DataModel<T>]) {
debugPrint(data)
}
}
Though this solves the issue at line renderUI(data: data)
I get new error now at delegate?.fetchedData(data: someObjects)
Cannot convert value of type '[DataModel<SKProduct>]' to expected argument type '[DataModel<(any SomeProtocol).DataType>]'
Member 'fetchedData' cannot be used on value of type 'any SomeProtocol'; consider using a generic constraint instead
The problem is that the generic method in
SomeProtocol
can accept any typeT
but therenderUI
can accept only the type thatSomeViewController
has been initialized with.For example, if you define
SomeViewController<String>
thenSomeProtocol
says you should be able to callfetchedData<Int>
which would then have to pass anInt
toSomeViewController<String>
.There is no simple way to fix it, the architecture must be changed depending on what you really need.
Maybe:
is what you want for the view controller. However, that wouldn't work with the data provider without changes.