提问人:Sandeep Bhandari 提问时间:11/15/2023 最后编辑:Sandeep Bhandari 更新时间:11/17/2023 访问量:71
无法将类型为“[DataModel<T>]”的值转换为预期的参数类型“[DataModel<T>]”
Cannot convert value of type '[DataModel<T>]' to expected argument type '[DataModel<T>]'
问:
我有一个数据模型,产品可以根据实验(AB 测试)进行更改,所以我有一个带有泛型的结构
struct DataModel<T: Sendable & Equatable> {
var product: T?
// there are other properties,
}
我有数据提供程序和协议
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)
}
}
最后是 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)
}
}
但是我在行上收到以下错误renderUI(data: data)
Cannot convert value of type '[SomeRandomProject.DataModel<T>]' to expected argument type '[SomeRandomProject.DataModel<T>]'
编辑1:
按照下面@Sulthan的回答,我将代码修改为
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)
}
}
虽然这解决了行的问题,但我现在在renderUI(data: data)
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
答:
问题在于泛型方法可以接受任何类型,但只能接受已初始化的类型。SomeProtocol
T
renderUI
SomeViewController
例如,如果定义 then 说您应该能够调用,则必须将 a 传递给 .SomeViewController<String>
SomeProtocol
fetchedData<Int>
Int
SomeViewController<String>
没有简单的方法可以修复它,必须根据您的实际需求更改架构。
或:
protocol SomeProtocol: AnyObject {
associatedtype DataModelType: Sendable & Equatable
func fetchedData(data: [DataModel<DataModelType>])
}
是视图控制器所需的内容。但是,如果不进行更改,这将不适用于数据提供程序。
评论
associatedtype
SomeProtocol
associatedtype
DataModel
这是我解决这个问题的方法,不确定这是否有效甚至正确的方法,但到目前为止,这解决了我在问题中提到的问题。如果我将来遇到这种方法的任何问题,我可能会卷土重来并更新答案以反映相同的问题。
正如 Sulthan 所建议的那样,我决定使用 in 协议进行修复(在上面的答案中很好地解释了为什么会发生此错误以及它意味着什么)associatedtype
Cannot convert value of type '[SomeRandomProject.DataModel<T>]' to expected argument type '[SomeRandomProject.DataModel<T>]'
但是在协议中使用关联类型的问题是,您不能将协议用作具体类型,因此编译器将强制您使用,如我的问题编辑 1 所示。这显然会导致any
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
ON声明delegate?.fetchedData(data: someObjects)
因为具有关联类型的协议不能用作具体类型,所以我决定引入一个代理类并使其确认SomeProtocol
class SomeProxyClass<T: Equatable>: SomeProtocol {
typealias DataType = T
var fetchDataCompletionBlock: (([DataModel<T>]) -> ())?
func fetchedData(data: [DataModel<DataType>]) {
fetchDataCompletionBlock?(data)
}
}
现在更新了我的 DataProvider 以保存类型的委托而不是 SomeProtocolSomeProxyClass<T>
class DataProvider<T: Equatable> {
weak var delegate: SomeProxyClass<T>?
func getData() {
delegate?.fetchedData(data: [DataModel(value: 100 as! T)])
}
}
最后,在我的 ViewController 中,我实例化了 的实例并将其作为委托传递给 。但是现在,当 DataProvider 获取数据时,它将通知而不是我的 ViewController。为了从我的 ViewController 回调,我使用了闭包,例如SomeProxyClass<T>
DataProvider
SomeProxyClass
SomeProxyClass
fetchDataCompletionBlock
整体代码如下所示
struct DataModel<T: Equatable> {
let value: T
}
class ViewController1<T: Equatable>: UIViewController {
func someFunction() {
let dataProvider = DataProvider<T>()
let proxyInstance = SomeProxyClass<T>()
proxyInstance.fetchDataCompletionBlock = {[weak self] dataArray in
debugPrint("do whatever you want with \(dataArray)")
}
dataProvider.delegate = proxyInstance
dataProvider.getData()
}
}
protocol SomeProtocol: AnyObject {
associatedtype DataType: Equatable
func fetchedData(data: [DataModel<DataType>])
}
class SomeProxyClass<T: Equatable>: SomeProtocol {
typealias DataType = T
var fetchDataCompletionBlock: (([DataModel<T>]) -> ())?
func fetchedData(data: [DataModel<DataType>]) {
fetchDataCompletionBlock?(data)
}
}
class DataProvider<T: Equatable> {
weak var delegate: SomeProxyClass<T>?
func getData() {
delegate?.fetchedData(data: [DataModel(value: 100 as! T)])
}
}
评论