首页 > 解决方案 > 无法执行存储在 Array[Any] 中的对象的方法

问题描述

我想将不同类型的对象存储在一个数组中。下面的程序只是一个最小的演示。在 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'

好吧,在编译时对象的类型是未知的。这就是编译器抱怨的原因。如何告诉编译器可以访问存储对象的属性?

标签: iosswiftcastinganyanyobject

解决方案


区别来自于类型检查的区别:

  • 运行时,或
  • 编译时间

运算符在is运行时检查表达式是否可以转换为指定的类型。type(of:)在运行时检查确切的类型,而不考虑子类。

anyArray[0].name由于 TypeAny没有name属性,因此无法编译。

如果您确定anyArray[0]是 a 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协议。

要了解有关协议的更多信息,请查看此处


推荐阅读