迅速无法转换类型的值

时间:2018-07-16 05:27:12

标签: ios swift uitableview generics

我有很多TableViewCells,一个是基类

BaseTableViewCell<T: BaseTableViewItem>: UITableViewCell{
    public var item: T!
}

另一个是类似的子类

ATableViewCell: BaseTableViewCell<ATableViewItem>

BTableViewCell: BaseTableViewCell<BTableViewItem>

ATableViewItem和BTableViewItem是BaseTableViewItem的子类

问题是

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   var cell = tableView.dequeueReusableCell(withIdentifier: item.cellIdentifier)
   (cell as! BaseTableViewCell).item.title = "title"
   return cell!;
}

并在cell as! BaseTableViewCell

中崩溃
  

无法将类型“ Example.ATableViewCell”(0x1078453f0)的值强制转换为“ Example.BaseTableViewCell”

我该怎么办?

ps: 之所以这样做,是因为我想改进项目https://github.com/JavenZ/ZJTableViewManager,在这个项目中,当我使用自定义单元格时,总是像let item = self.item as! ZJTextItem这样写代码,我觉得使用起来有些棘手。 所以我尝试使用泛型。看来我还没有找到好方法。您可以在ZJTableViewManager中查看演示。 非常抱歉我的英语不好,我无法清楚表达自己的意思

2 个答案:

答案 0 :(得分:1)

您似乎正在尝试将子类转换为其父类,这是不可能的。您可以向下转换(将超类广播到其子类),因为该子类具有与其父类相同的属性,因此,该超类实例的所有信息都可以在该子类的实例中找到位置。但是,子类中可以包含比父类更多的信息,因此其所有信息可能无法在父类中找到位置。

我也看不出为什么这样做是必要的。在将对象的类型指定为一个类的任何地方,都可以在其位置使用其子类。如果需要使用子类中超类的重写方法,则可以始终使用super关键字。我不明白为什么需要进行向上转换(从子类到超类,您在做什么)。如果您可以阐明原因,也许我可以提供更多帮助,但是如果不必要的话,您应该避免up头。

答案 1 :(得分:0)

您只能转换彼此严格的子类/超类的东西。

例如,如果我有

class MyCell: UITableViewCell { ... }

那我可以说

let cell: UITableViewCell = MyCell()  // Swift knows that MyCell inherits from `UITableViewCell`

我可以说

var someCell: UITableViewCell

...

let myCell = someCell as? MyCell  // Swift knows that this might work 

但是你不能说类似这样的话

let s: String = someCell 

这些类型无关。

在您的情况下,您已经引入了泛型,因此,即使基本类位于继承链中,添加泛型变体也意味着它们不兼容。我不能这样说:

let cell: ATableViewCell<Int> = ATableViewCell<String>() 

它们是不同的。

这样做会违反Liskov Substitution Principle

考虑一个简单的通用类:

class SomeClass<T> {
    var item:T

    init(item: T) {
        self.item = item
    }
}


let a = SomeClass<Int>(item: 10)

print(a.item+10)   // Prints 20

let b = SomeClass<String>(item: "10")

print(b.item+10)  // Compiler error - You can't add a string and an integer

您可以看到我需要知道与泛型一起使用的特定 type ,以便了解可以进行哪些操作。我无法将SomeClass<String>的实例分配给声明为SomeClass<Int>的变量;有效操作集不兼容。

您也许可以使用具有关联类型的协议,然后使用类型擦除,以便可以将该协议与子类一起使用,但是在某些时候,您需要了解特定行中要处理的单元格的具体类型因此您将需要将dequeueReusableCell的结果强制转换为该具体类。泛型和协议可能只会使事情变得更复杂。