我正在尝试投射一个协议类型的“过滤”数组
我有一系列符合几种不同协议的结构(评估,级别和门) - 可分级,可重复和可测试:
protocol Stageable
{
var index : Int { get }
var steps : [Step] { get }
}
protocol Testable
{
var threshold : Float { get }
}
protocol Repeatable
{
var sessions: Int { get }
}
struct Gate : Stageable, Testable, Repeatable
{
private(set) var index : Int
private(set) var steps : [Step]
private(set) var threshold : Float
private(set) var sessions : Int
}
struct Assessment : Stageable, Testable
{
private(set) var index : Int
private(set) var steps : [Step]
private(set) var threshold : Float
}
struct Level : Stageable, Repeatable
{
private(set) var index : Int
private(set) var steps : [Step]
private(set) var sessions : Int
}
Step是另一个结构。没有使用任何课程。
这些结构在添加到数组之前就已填充。 数组通常采用[Assessment,Gate,Level,Level]的形式。所有结构数据都是从XML文件中填充的。
在某些情况下,我只想查看数组中的“级别”,所以我这样做:
// stages = [Assessment, Gate, Level, Level, ...]
let levels = stages.filter{ $0 is Level }
如果我查询这个,它看起来很好,例如levels.count是我的期望。 但是,如果我现在想要将数组转换为[Level],它会崩溃并出现以下错误:
fatal error: can't unsafeBitCast between types of different sizes
这是因为我从协议转换为结构类型吗?我也觉得我已经错过了协议的主要好处,必须有更好的方法来做到这一点。
目前正在使用Xcode 7 beta 5.
答案 0 :(得分:6)
转换结构数组是有问题的,因为结构是值类型。这意味着结构数组的每个元素占用内存中结构的大小。这对于标准对象的数组是不同的,因为它们通过引用传递。对象数组中的每个元素都是一个引用(指向特定内存区域的指针)。
为了证明这一点,请考虑以下
class ABC {
private var i = 0
private var j = 1
private var k = 2
}
print(sizeof(UIViewController))
print(sizeof(UIImage))
print(sizeof(NSObject))
print(sizeof(ABC))
每个print
语句在我的平台上输出8
,这是内存地址的大小(显然不同于此类实例占用的内存量)。
另一方面,当我从您的问题中获取代码并执行
时print(sizeof(Stageable))
print(sizeof(Level))
我分别得到40
和24
,它们是内存中这些结构的实例大小。这意味着类型[Stageable]
的数组由40字节元素的块组成,而类型[Level]
的数组由24字节元素的块组成。因此,您无法在这些数组类型之间进行转换,因为这需要重写数组的内存。
作为替代方法,您可以使用map
方法强制进行类型转换:
let levels = stages.filter({ $0 is Level }).map({ $0 as! Level })
通过利用flatMap
方法:
let levels = stages.flatMap({ $0 as? Level })
答案 1 :(得分:0)
好吧,当你执行这段代码时:
let levels = stages.filter{ $0 is Level }
您的levels
类型变为[Stageable]
。现在,要将[Stageable]
转换为[Level]
,您可以使用以下代码:
var l = levels.map{ $0 as! Level }