ios - 如何在 Swift 中向下转换/转换结构的泛型类型

标签 ios objective-c swift

我已经将我使用 UICollectionViewCells 的工作重构为以下内容

struct CollectionViewCellModel<T: UICollectionViewCell> {
    let reuseIdentifier: NSString
    let allowsSelection: Bool

    // Optional callbacks
    var onCreate: ((T) -> Void)?            = nil
    var onSelection: ((T) -> Void)?         = nil
    var onWillBeDisplayed: ((T) -> Void)?   = nil
    var onDelete: ((T) -> Void)?            = nil

    // Create cell
    func toCell(collectionView: UICollectionView, indexPath: NSIndexPath) -> T {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as T
        if let onCreate = onCreate { onCreate(cell) }
        return cell
    }
}

这让我更容易创建特定单元格的列表(对于表单之类的东西),然后使用它们。

但是,我一直对如何存储这些对象感到困惑。我不能将它们向下转换为 CollectionViewCellModel<UICollectionViewCell>因此无法存储 [CollectionViewCellModel<UICollectionViewCell> 的列表

我以为 Swift 支持向下转型,但显然不支持泛型类型?

let cell = CollectionViewCellModel<A>(...)
let genericCell = cell as CollectionViewCellModel<UICollectionViewCell>
// ERROR: UICollectionViewCell is not identical to A
let genericMaybeCell = cell as? CollectionViewCellModel<UICollectionViewCell>
// ERROR: UICollectionViewCell is not identical to A

我是否必须将这些存储为 Any 的数组?然后每次都施放它们,还是我只是误会了什么(或两者都有)?


更新:我在 Playground 上做了一些工作来清楚地说明我的意思:

protocol IA {
    func name() -> String
}

class A:IA { func name() -> String { return "A (Base)" } }
class B: A { override func name() -> String { return "B (Child of A)" } }
class C: B { override func name() -> String { return "C (Child of B)" } }

struct SA<T: A> {
}

let struct0: Any = SA<B>()
// OK: yes, the struct of B is an Any! 
// but since B inherits from A, isn't it safe to 
// say that SA<B> is also of type SA<A>?
let struct1: SA<A> = SA<B>() as SA<A>
// NO
// ERROR: 'B' is not identical to 'A'
let struct1Optional: SA<A> = SA<B>() as? SA<A>
// not even optionally? NO
// ERROR: 'B' is not identical to 'A'

我想这是不可能的。也许在 Swift 1.3 中。请参阅评论中的线程。

更新(2/17/15)


对于那些对我为什么要这样做感兴趣的人,您必须了解我是如何使用我的 CollectionViewControllers (CVC) 的。我已经抽象出一个基本 CVC 来执行每个屏幕需要的通用方法。此 CVC 的协议(protocol)需要 Factory创建 CVC 模型。这些模型知道如何 self 转换、响应 Action ,并且非常像 Controller 。他们很胖而且很活跃。另一方面,我的观点都是愚蠢的。他们只知道如何在屏幕上移动内容或进入不同的显示状态。从 CVC 配置单元格时,您最终会执行这些大的 switch 语句,从可读性的角度来看,这些语句实际上并没有告诉您太多信息,期望“route this”。更糟糕的是你开始在那里配置你的 View 。这并不可怕,但一般来说——对我来说—— View Controller 控制着它所负责的 View 。虽然这个 VC 可能是单元的父 VC,但这并没有给它适当的访问权限来大量操作它。这现在让你的 VC 做类似 cell.changeDisplayToActiveState() 的事情。 ;简而言之,它现在承担着控制其子细胞的重任。这就是促成所有“胖”风投的原因。我首先选择通过采用 VIPER 来偏离这条道路。模式,但我发现它太过分了——尤其是对于一个新项目。我放弃了它并开始使用基本 CVC。目前我的项目是这样工作的:

  • 基本 CVC 需要工厂,工厂需要 CVC(从而促进单元格的双向绑定(bind))
  • 这家工厂为 CVC 生产电池和接头模型。
  • 这些模型中嵌入了回调、数据和配置功能。
  • 他们可以从这些回调中调用 View Controller 的 PUBLIC 函数(因此严格分离职责),例如 vc.changeDisplayState(...)changeToVc(...)

最佳答案

我不确定您究竟在寻找什么,但我会尽量回答。大概您对存储一堆 CollectionViewCellModel<X> 不感兴趣用于某些特定的 X ,因为这样就可以回答“我如何存储它们?”会很简单:[CollectionViewCellModel<X>] .所以我猜你想要一个 CollectionViewCellModel<T> 的数组对于异构T的。实现这一目标的最佳方法是提供所有 CollectionViewCellModel<T>是一个通用协议(protocol)(或基类,但在您的情况下它们是 struct s,所以不是那样),大致如下:

protocol CollectionViewCellModelType {
  var reuseIdentifier: NSString {get}
  var allowsSelection: Bool {get}

  func toCell(
    collectionView: UICollectionView, indexPath: NSIndexPath
  ) -> UICollectionViewCell
}

struct CollectionViewCellModel<T: UICollectionViewCell>
  : CollectionViewCellModelType {
  let reuseIdentifier: NSString
  let allowsSelection: Bool

  // Optional callbacks
  var onCreate: ((T) -> Void)?            = nil
  var onSelection: ((T) -> Void)?         = nil
  var onWillBeDisplayed: ((T) -> Void)?   = nil
  var onDelete: ((T) -> Void)?            = nil

  // Create cell
  func toCell(
    collectionView: UICollectionView, indexPath: NSIndexPath
  ) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(
      reuseIdentifier, forIndexPath: indexPath) as! T

    if let onCreate = onCreate { onCreate(cell) }
    return cell
  }
}

var a: [CollectionViewCellModelType] = [] // put them in here

希望对您有所帮助,

戴夫

关于ios - 如何在 Swift 中向下转换/转换结构的泛型类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28503963/

相关文章:

ios - 围绕原点旋转整个 SKView

ios - .observe firebase 方法 swift4 后代码未执行

ios - 是否有任何框架/库可用于为我的 iOS 应用程序实现 "take a tour"功能

ios - 在 Swift 中创建 NEVPNManager 对象时出现问题

iphone - 比较 NSNumber

objective-c - 测试我的数组在给定索引处是否为零?

ios - swift 中的 CollectionViewFlowLayout 的 collectionViewContentSize()

ios - UITableViewCell 按钮单击在 TableView 控件的多个部分中触发

ios - UITableViewCell 对 indexPath 的更改不正确

ios - 在 Safari 和 IOS 中使用 "Gifs": Videos won't autoplay