无法将类型为“[DataModel<T>]”的值转换为预期的参数类型“[DataModel<T>]”

Cannot convert value of type '[DataModel<T>]' to expected argument type '[DataModel<T>]'

提问人:Sandeep Bhandari 提问时间:11/15/2023 最后编辑:Sandeep Bhandari 更新时间:11/17/2023 访问量:71

问:

我有一个数据模型,产品可以根据实验(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
Swift 泛型可 发送

评论


答:

1赞 Sulthan 11/15/2023 #1

问题在于泛型方法可以接受任何类型,但只能接受已初始化的类型。SomeProtocolTrenderUISomeViewController

例如,如果定义 then 说您应该能够调用,则必须将 a 传递给 .SomeViewController<String>SomeProtocolfetchedData<Int>IntSomeViewController<String>

没有简单的方法可以修复它,必须根据您的实际需求更改架构。

或:

protocol SomeProtocol: AnyObject {
    associatedtype DataModelType: Sendable & Equatable

    func fetchedData(data: [DataModel<DataModelType>])
}

是视图控制器所需的内容。但是,如果不进行更改,这将不适用于数据提供程序。

评论

1赞 Sandeep Bhandari 11/15/2023
这是有道理的:|我尝试了协议,但这是一个遗留代码,并且有很多地方在变量声明中用作具体类型:|一旦我宣布生病,就开始出现问题associatedtypeSomeProtocolassociatedtype
0赞 Sandeep Bhandari 11/15/2023
期望是我应该能够根据实验结果将 SKProduct 或 SomeOther 对象作为我现有对象的一部分传递。这里还有什么更好的架构呢?DataModel
0赞 Sandeep Bhandari 11/17/2023
感谢您的建议:)接受了您的回答,因为它正确地指出了错误消息中的问题,我已经发布了我自己的修复程序,但不确定它是否有效甚至正确的处理方法,但无论如何,您的回答指导我解决问题:)所以谢谢你
0赞 Sandeep Bhandari 11/17/2023 #2

这是我解决这个问题的方法,不确定这是否有效甚至正确的方法,但到目前为止,这解决了我在问题中提到的问题。如果我将来遇到这种方法的任何问题,我可能会卷土重来并更新答案以反映相同的问题。

正如 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>DataProviderSomeProxyClassSomeProxyClassfetchDataCompletionBlock

整体代码如下所示

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)])
    }
}