我想在数组中存储不同类型的对象。 下面的程序只是一个最小的演示。在anyArray:[Any]中存储Object1的实例。打印语句将打印出预期的对象类型。在下面的代码行中,对存储对象类型的测试返回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'
那么,在编译时对象的类型是未知的。这就是编译器抱怨的原因。如何告诉编译器可以访问存储对象的属性?
答案 0 :(得分:2)
您的对象仍然是Any
类型。您只是检查了它是否可以为Object1
类型,但没有进行强制转换。如果您希望该对象为Object1
,则需要投射。
如果多个类可以具有名称,则需要使用Protocol
(如@vadian在其注释中提到的那样)并将其转换为该协议。
protocol NameProtocol {
var name: String {get set}
}
class Object1: NameProtocol {
var name = "Object1"
}
if let testResult = anyArray[0] as? NameProtocol {
print(testResult.name)
}
编辑: “我要在数组中存储不同类型的对象”。如果您所有的对象都被标记为正确的解决方案将不起作用不符合该协议。
答案 1 :(得分:2)
差异来自与类型检查在以下方面的差异:
is
运算符在运行时检查是否可以将表达式强制转换为指定的类型。 type(of:)
在运行时检查确切的类型,而无需考虑子类。
anyArray[0].name
无法编译,因为类型Any
没有name
属性。
如果您确定anyArray[0]
是Object1
,则可以使用下垂运算符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。