Swift T不同的泛型对象的异构数组

Swift T不同的泛型对象的异构数组,swift,generics,collections,Swift,Generics,Collections,这就是我的类BaseSection实现集合的方式,它看起来是这样的: class BaseSection<T:Equatable> { var items:[T]? required init(items:[T]){ self.items = items } } let sectionTop = BaseSection<TopItem>(items:["foo","bar","yo"]) let sectionBottom = BaseSection<

这就是我的类
BaseSection
实现
集合的方式,它看起来是这样的:

class BaseSection<T:Equatable> {

var items:[T]?

required init(items:[T]){
   self.items = items
  }
}

let sectionTop = BaseSection<TopItem>(items:["foo","bar","yo"])
let sectionBottom = BaseSection<BottomItem>(items:["foo","bar","yo"])
我为许多解决方案奋斗了数小时,但在这里无法实现我的目标。 任何帮助都将不胜感激

Edit: I have uploaded the sample code to gitHub so you can get a better grasp of what im doing 

因为在swift自定义泛型类型中,所有泛型类型都是不变性的,这意味着
BaseSection
BaseSection
之间没有关系,所以这两种类型中唯一常见的是
Any
,您可以按照注释中的链接获取更多信息,作为总结

  • 数组/Dict是协方差
  • 闭包参数类型为逆变,闭包返回类型为协方差
  • 自定义泛型类型是不变性的

  • 另外,数组/Dict是struct,这意味着它们是按值传递的,因此可以安全地将它们视为协方差,因为在swift中,自定义泛型类型都是不变性的,这意味着
    BaseSection
    BaseSection
    没有关系,因此这两种类型中唯一常见的是
    Any
    ,您可以按照评论中的链接获取更多信息,作为摘要

  • 数组/Dict是协方差
  • 闭包参数类型为逆变,闭包返回类型为协方差
  • 自定义泛型类型是不变性的

  • 另外,数组/Dict是struct,这意味着它们是按值传递的,因此可以安全地将它们视为协方差,您似乎正在构建的是一种机制,用于在数据更改时自动进行表视图更改。非常普遍。我强烈建议您在计算更改时查看一个有用的起点。(在我自己的代码中,我使用了ListDiff的重写版本,因此这里的示例没有经过测试,但应该非常接近。)

    目标是创建一组更新操作(从ListDiff示例复制):

    这里重要的是,您有一系列的删除、插入和移动操作。您可以将这些应用于具有以下内容的表视图:

    extension UITableView {
        func applyChanges(from changeset: Result, forSection section: Int = 0) {
            beginUpdates()
    
            let deletes = changeset.deletes.map { IndexPath(row: $0, section: section) }
            deleteRows(at: deletes, with: .bottom)
    
            let inserts = changeset.deletes.map { IndexPath(row: $0, section: section) }
            insertRows(at: inserts, with: .none)
    
            for move in changeset.moves {
                guard !changeset.deletes.contains(move.from) else { continue }
                moveRow(at: IndexPath(row: move.from, section: section), 
                        to: IndexPath(row: move.to, section: section))
            }
    
            endUpdates()
        }
    }
    

    这里的关键点是,对于动画,您只需要索引路径。你实际上并不需要这些数据。因此,计算索引路径并传递它们。不需要泛型。

    您似乎正在构建的是一种随着数据更改而自动更改表视图的机制。非常普遍。我强烈建议您在计算更改时查看一个有用的起点。(在我自己的代码中,我使用了ListDiff的重写版本,因此这里的示例没有经过测试,但应该非常接近。)

    目标是创建一组更新操作(从ListDiff示例复制):

    这里重要的是,您有一系列的删除、插入和移动操作。您可以将这些应用于具有以下内容的表视图:

    extension UITableView {
        func applyChanges(from changeset: Result, forSection section: Int = 0) {
            beginUpdates()
    
            let deletes = changeset.deletes.map { IndexPath(row: $0, section: section) }
            deleteRows(at: deletes, with: .bottom)
    
            let inserts = changeset.deletes.map { IndexPath(row: $0, section: section) }
            insertRows(at: inserts, with: .none)
    
            for move in changeset.moves {
                guard !changeset.deletes.contains(move.from) else { continue }
                moveRow(at: IndexPath(row: move.from, section: section), 
                        to: IndexPath(row: move.to, section: section))
            }
    
            endUpdates()
        }
    }
    

    这里的关键点是,对于动画,您只需要索引路径。你实际上并不需要这些数据。因此,计算索引路径并传递它们。不需要泛型。

    相关:如果您有
    部分
    ,您打算如何处理它?您将无法访问其元素的
    items
    属性,因为类型不一致。(解决方案包括将
    转换为?
    所有内容都是错误的,应该重新思考。)有了对
    部分
    的预期操作(特别是您计划对其元素的操作),我们可以讨论它应该是什么类型。@user28434有趣的文章:)我同意Rob,现在还不清楚你想对阵列做什么,这并不是我想要的。我的意思是,从字面上看,你认为自己在写什么代码来消费
    部分
    ?您将无法访问
    项目
    (至少不能访问
    TopItem
    BottomItem
    ),那么您将如何处理它?您的调用代码将驱动您如何构造它。(这里的意思是,你几乎肯定想要一个协议,但我必须知道你想要这个协议做什么。)相关:如果你有
    部分
    ,你打算用它做什么?您将无法访问其元素的
    items
    属性,因为类型不一致。(解决方案包括将
    转换为?
    所有内容都是错误的,应该重新思考。)有了对
    部分
    的预期操作(特别是您计划对其元素的操作),我们可以讨论它应该是什么类型。@user28434有趣的文章:)我同意Rob,现在还不清楚你想对阵列做什么,这并不是我想要的。我的意思是,从字面上看,你认为自己在写什么代码来消费
    部分
    ?您将无法访问
    项目
    (至少不能访问
    TopItem
    BottomItem
    ),那么您将如何处理它?您的调用代码将驱动您如何构造它。(这里的意思是,你几乎肯定想要一个协议,但我必须知道你想要这个协议做什么。)谢谢你的回答!你注意到我的阵列结构了吗?它包含两个具有不同对象的数组。INT数组将非常容易实现只要将代码上传到github,如果您介意的话,我不确定如何处理您发布的代码。这里还有问题吗?其中似乎没有任何内容需要多种类型的数组。我甚至不明白为什么BaseSection是通用的;它只保存[BaseItem],所以让它保存[BaseItem]。这里混合了协议、子类和泛型。这太复杂了,会一次又一次地咬你。如果需要子类,只需使用子类即可。没有必要在这之上引入泛型和协议。对标题问题的简短回答是:你不能这样做,重新设计,所以你不需要这样做。(有很多通用的tableview处理程序不需要这样做;我自己在Swift中构建它们。如果您不想构建自己的,请参阅一个非常强大的处理程序。它在O中
    extension UITableView {
        func applyChanges(from changeset: Result, forSection section: Int = 0) {
            beginUpdates()
    
            let deletes = changeset.deletes.map { IndexPath(row: $0, section: section) }
            deleteRows(at: deletes, with: .bottom)
    
            let inserts = changeset.deletes.map { IndexPath(row: $0, section: section) }
            insertRows(at: inserts, with: .none)
    
            for move in changeset.moves {
                guard !changeset.deletes.contains(move.from) else { continue }
                moveRow(at: IndexPath(row: move.from, section: section), 
                        to: IndexPath(row: move.to, section: section))
            }
    
            endUpdates()
        }
    }