2017-10-14 54 views
0

我有2 structs只有通过协议相关。我试图在两种类型之间进行转换,因为它们共享一个协议,但是我得到一个运行时错误。仅使用协议在类型之间进行转换?

这就是我想要做的事:

protocol A { 
    var id: String { get } 
    var name: String { get } 
    var isActive: Bool { get set } 
} 

struct Entity: A { 
    let id: String 
    var name: String 
    var isActive: Bool 

    func someFun() { 
     print("\(name), active: \(isActive)") 
    } 
} 

struct ViewModel: A { 
    let id: String 
    var name: String 
    var isActive: Bool 
} 

let vm = ViewModel(id: "abc", name: "John Doe", isActive: true) 
let pt = vm as A 
let et = pt as! Entity 
print(et.someFun()) //crash 

我得到的错误是:

Could not cast value of type '__lldb_expr_87.ViewModel' (0x111835638) to '__lldb_expr_87.Entity' (0x111835550). 

这是一个真正的无赖,因为如果我有几百万的记录,我不我想要循环每一个手动转换一个。我希望能暗中神奇投这样的:

let entity = vm as A as Entity 
let entities = vms as [A] as [Entity] 

任何性能敏感的方式来传递边界之间的对象,而不通过每一个循环?

+0

你不能那样做,因为协议只保证两种类型都实现了协议要求。它并不能保证两种类型都是可以互换的。顺便提一下,Swift提供了'map'之类的函数来避免循环(尽管框架使用循环)。 – vadian

回答

0

正如vadian在他的评论中所述,您不能像这样类型化。要执行你正在尝试通过类型转换做的,你需要做这样的事情:

let entity = Entity(id: vm.id, name: vm.name, isActive: vm.isActive) 

let entities = vms.map { 
    return Entity(id: $0.id, name: $0.name, isActive: $0.isActive 
} 

你之所以是崩溃是因为类型转换不会更改的对象实际上具有的属性和方法,只有他们访问的方法和属性。如果您执行以下,你会失去你的someFun访问()方法:

let entityAsA = Entity(id: "id", name: "name", isActive: true) as A 

然而,以下将编译和运行没有崩溃:

(entityAsA as! Entity).someFun() 

所以,当你试图从投ViewModel to A to Entity,它不会改变值在内存中创建的方式(不能访问称为someFun()的函数),并且每次都会崩溃。

相关问题