无法将swift泛型子类转换为泛型超类

无法将swift泛型子类转换为泛型超类,swift,xcode,generics,Swift,Xcode,Generics,我想在Swift中使用参数化类编写更好、更清晰的代码,但我遇到了一个奇怪的构建错误: 无法将“CustomAdapter”类型的值转换为预期的参数类型“TableTestParameterizedAdapter” 我真正想要的是能够使用一个方法(在适配器子类中重写)创建一个基本适配器类,该方法用于将单元格子类与相应的数据模型绑定,并避免每次强制转换 为了更好地理解我的意思,我将在下面发布代码 class TestParametrizedAdapter<C>: NSObject {

我想在Swift中使用参数化类编写更好、更清晰的代码,但我遇到了一个奇怪的构建错误:

无法将“CustomAdapter”类型的值转换为预期的参数类型“TableTestParameterizedAdapter”

我真正想要的是能够使用一个方法(在适配器子类中重写)创建一个基本适配器类,该方法用于将单元格子类与相应的数据模型绑定,并避免每次强制转换

为了更好地理解我的意思,我将在下面发布代码

class TestParametrizedAdapter<C>: NSObject {

    func doSmth(cell: C) {

    }

}

class TableTestParametrizedAdapter<C>: TestParametrizedAdapter<C> where C:ETableViewCell {

}

class PeopleTableViewCell: ETableViewCell {

}

class CustomAdapter: TableTestParametrizedAdapter<PeopleTableViewCell> {

    override func doSmth(cell: PeopleTableViewCell) {

    }
}


class TestBaseController: UIViewController {

    var adapter: TableTestParametrizedAdapter<ETableViewCell>?

    override func viewDidLoad() {
        super.viewDidLoad()

        setAdapter(adapter: CustomAdapter()) // this is the line with build error
    }

    func setAdapter(adapter: TableTestParametrizedAdapter<ETableViewCell>) {
        self.adapter = adapter
    }
}
类testParameterizedAdapter:NSObject{
func doSmth(单元格:C){
}
}
类TableTestParameterizedAdapter:TestParameterizedAdapter,其中C:ETableViewCell{
}
类PeopleTableViewCell:ETableViewCell{
}
类CustomAdapter:TableTestParameterizedAdapter{
覆盖func doSmth(单元格:PeopleTableViewCell){
}
}
类TestBaseController:UIViewController{
var适配器:TableTestParameterizedAdapter?
重写func viewDidLoad(){
super.viewDidLoad()
setAdapter(adapter:CustomAdapter())//这是生成错误的行
}
func setAdapter(适配器:TableTestParameterizedAdapter){
self.adapter=适配器
}
}
我在其他一些帖子上读到过这方面的文章,有人指出
GenericClass
GenericClass)

Anywat,有什么解决办法吗?在这种情况下,我们如何使用Swift的参数化功能?我使用Swift 4


提前感谢。

即使Swift支持自定义泛型中的差异,您的代码也将是错误的,因为您尝试使用只能处理PeopleTableViewCell实例的对象,而不是可以处理任何ETableViewCell的对象。如果这确实是您想要的,并且您不介意一些运行时检查,那么您可以通过少量的类型擦除来执行类似的操作:

class TestAnyAdapter: NSObject {
    func doSmth(cell: Any) {}
}

class TableTestParametrizedAdapter<C>: TestAnyAdapter where C:ETableViewCell {
    override func doSmth(cell: Any) {
        guard let cell = cell as? C else {
            return
        }

        self.doSmth(cell: cell)
    }

    func doSmth(cell: C) {}
}
类TestAnyAdapter:NSObject{
func-doSmth(单元格:任意){}
}
类TableTestParameterizedAdapter:TestAnyAdapter,其中C:ETableViewCell{
覆盖func doSmth(单元格:任意){
防护装置let单元=单元为?C else{
返回
}
self.doSmth(单元格:单元格)
}
func-doSmth(单元:C){}
}

其余的代码将与您已有的代码相同,只是没有编译时错误。

我同意Konstantin的基本观点。这个代码根本不正确,斯威夫特告诉你这一点
CustomAdapter.doSmth
不能接受任何任意的
ETableViewCell
,但
adapter
声明必须接受

根据您试图解决的实际问题,有许多解决方案。您表示希望编写“更好、更干净的代码”,这意味着您在现有代码中发现了过多的重复或强制转换。因此,您要做的是查看这些代码,并查看哪些代码被复制,然后我们可以帮助您设计通用解决方案以避免这种复制。这个问题没有普遍的答案;在一个方向上所做的抽象选择会使其他方向的灵活性降低。抽象是选择;它们需要在上下文中做出

在Swift中,您应该避免依赖子类化。有一些是必需的,因为要桥接到ObjC,但是关注Swift的代码应该避免子类。在您的特定示例中,有趣的类只有一个函数。如果这是真的,那么实现它就很容易了。使用一个功能:

func customAdapter(cell: PeopleTableViewCell) {}

class TestBaseController: UIViewController {
    let adapter: (PeopleTableViewCell) -> Void = customAdapter
}
“但我真正的问题比这更复杂!”好吧。然后我们必须谈谈你真正的问题。正确地将这些东西抽象为最简单的形式,应该会得到最简单的解决方案。如果事情实际上有点复杂,可以使用结构和协议

protocol Adapter {
    associatedtype Cell: UITableViewCell
    func doSmth(cell: Cell)
}

struct CustomAdapter<Cell: ETableViewCell>: Adapter {
    func doSmth(cell: Cell) {}
}

class TestBaseController: UIViewController {
    let adapter: CustomAdapter<PeopleTableViewCell> = CustomAdapter()
}
协议适配器{
关联类型单元格:UITableViewCell
func doSmth(单元格:单元格)
}
结构自定义适配器:适配器{
func-doSmth(cell:cell){}
}
类TestBaseController:UIViewController{
let适配器:CustomAdapter=CustomAdapter()
}
我在掩饰你的问题,那就是如何使一个只接受
PeopleTableViewCell
的函数在需要接受任何
ETableViewCell
的函数时使用。那是不可能的。这不是Swift的限制;这是不可能的。正如康斯坦丁所解释的那样,你能做的最好的事情就是加上“什么也不做”或“崩溃”


如果您能更清楚地知道您试图修复的现有代码中的特定问题,我们可能会帮助您设计更好的解决方案。添加泛型本身并不能使您的代码“更好或更干净”(根据我的经验,大多数最好的解决方案根本不需要泛型)。

让我们试着弄清楚一些事实

  • 假设我们有泛型类
    C

  • 我们还有D类和D2类,其中D2是T的子类

那么
C
不是
C
的子类。它们只是不同的类型。(我们说不存在协方差。)

  • 假设我们的泛型类
    C
    有一个子类
    C2
然后,
C2
C
的子类,
C2
C
的子类

因此,只要参数化类型相同,就存在多态性。但是如果参数化类型不同,即使参数化类型是类和子类,也没有协方差

(Swift可选和Swift集合在此处获得特殊的协方差豁免,但这已经融入到语言中;您不能使用相同的豁免。)