我想在数组中存储不同类型的对象。以下程序只是最低限度的演示。在anyArray中:[Any]存储Object1的一个实例。 print语句打印出预期的对象类型。在以下行中,存储对象类型的测试返回true。这意味着,在运行时,正确的对象类型是已知的,并且每件事情似乎都很好。
class Object1 {
var name = "Object1"
}
var anyArray:[Any] = [Object1()]
print("\(type(of: anyArray[0]))")
let testResult = anyArray[0] is Object1
print("Test result:\(testResult)")
//print("Name:\((anyArray[0]).name)")
Console output:
Object1
Test result:true
但是,如果我尝试打印出对象的name属性,我会从编辑器中收到一条错误消息:
Value of type 'Any' has no member 'name'
好吧,在编译时,对象的类型是未知的。这就是编译器抱怨的原因。如何告诉编译器可以访问存储对象的属性?
差异来自与类型检查的区别:
is
运算符在运行时检查表达式是否可以转换为指定的类型。 type(of:)
在运行时检查确切的类型,而不考虑子类。
anyArray[0].name
没有编译,因为类型Any
没有name
属性。
如果你确定anyArray[0]
是Object1
,你可以使用downcast运算符as!
:
print("\((anyArray[0] as! Object1).name)")
要在运行时检查来自anyArray
的元素是否可以是Object1
,请使用可选绑定,使用条件转换运算符as?
:
if let object = anyArray[0] as? Object1 {
print(object.name)
}
guard
语句:
guard let object = anyArray[0] as? Object1 else {
fatalError("The first element is not an Object1")
}
print(object.name)
如果数组中的所有对象都具有name
属性,并且您不想重复执行可选绑定的所有环节,则使用协议。您的代码将如下所示:
protocol Named {
var name: String {get set}
}
class Object1: Named {
var name = "Object1"
}
var anyArray:[Named] = [Object1()]
print("\(type(of: anyArray[0]))")
let testResult = anyArray[0] is Object1
print("Test result:\(testResult)")
print("Name:\(anyArray[0].name)")
请注意,anyArray
现在是Named
对象的数组,并且Object1
符合Named
协议。
要了解有关协议的更多信息,请查看here。
你的对象仍然是Any
类型。你刚检查它是否可以是Object1
类型,但你没有投出它。如果你想将对象作为Object1
,你需要施放它。
此外,如果多个类可以具有名称,则需要使用qvxswpoi,如@vadian在评论中提到的并将其转换为该协议。
Protocol
编辑:“我想在数组中存储不同类型的对象”。如果您拥有的所有对象都不符合协议,则标记为正确的解决方案将不起作用。