[英]How to downcast / cast a struct's generic type in 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>
,因此无法存储[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
的数组,然后每次都将它们转换为或者我只是误解某些(或两者)?
更新:我在操场上做了一些工作,以清楚地说明我的意思:
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中。 请参阅评论中的主题。
更新(2015年2月17日)
对于那些对我为什么一开始就这样做感兴趣的人,你必须了解我是如何使用我的CollectionViewControllers(CVC)的。 我抽象了一个基础CVC来执行每个屏幕需要的常用方法。 此CVC具有一个协议,该协议需要Factory
创建CVC模型。 这些模型知道如何改变自己,对行动做出反应,并且非常像控制器。 他们很胖,很活跃。 另一方面,我的观点都是愚蠢的。 他们所知道的只是在屏幕上移动东西或进入不同的显示状态。 从CVC配置单元时,您最终会执行这些大的switch语句,这些语句实际上并没有从可读性角度告诉您“路由此”。 你开始在那里配置视图会变得更糟。 这并不可怕,但一般来说 - 对我来说 - 视图控制器控制它负责的视图 。 虽然这个VC可能是单元的父VC,但这并没有给它适当的访问权来大量操作它。 这现在让你的VC做像cell.changeDisplayToActiveState()
; 简而言之,它现在承担着控制其子细胞的负担。 这就是所有“肥胖”VC的贡献。 我首先采用VIPER
模式选择偏离这条道路,但我觉得它过度 - 特别是对于一个新项目。 我废弃它并开始使用基础CVC。 这是我的项目目前的工作方式:
vc.changeDisplayState(...)
或changeToVc(...)
我不确定你到底发生了什么,但我会尽力回答。 据推测,你对一些特定的X
存储一堆CollectionViewCellModel<X>
并不感兴趣,因为那时“我该如何存储它们?”的答案。 很简单: [CollectionViewCellModel<X>]
。 所以我猜你想要一个CollectionViewCellModel<T>
的数组用于异构T
实现这一目标的最佳方法是为所有CollectionViewCellModel<T>
提供一个通用协议(或基类,但在你的情况下,它们是struct
,所以不是那样),大致如下:
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
希望这有帮助,
戴夫
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.