【问题标题】:Check if `Any` value is object检查“任何”值是否为对象
【发布时间】:2016-08-27 19:25:46
【问题描述】:

我惊讶地发现这个条件总是成立的:

let foo: Any = 4
if let object = foo as? AnyObject {
    print("It's an object.")
    //do something with `object` that requires reference semantics
} else {
    print("It's not an object.")
}

看来不管foo原来是什么类型,都转换成对应类的实例了。有没有可靠的方法来确定foo 是否是一个对象?

【问题讨论】:

  • 这是在 Swift 3 中吗?如果是这样,请参阅AnyObject not working in Xcode8 beta6?
  • 链接的线程没有回答“如果Any是类实例或其他东西,我们如何区分它的内容?”的问题。为什么这被标记为“重复”?
  • @MartinR,OP 的描述是“是否有可靠的方法来确定 foo 是否是一个对象?”。不坚持使用isas?,所以可能还有别的办法。
  • 感谢@Hamish 的链接;很高兴知道我不是唯一一个对这种行为感到惊讶的人。

标签: swift casting


【解决方案1】:

更新

我在下面显示的代码被报告为在发布版本中不起作用。 (请参阅下面 Paul Cantrell 的评论。)

为我的“就我所测试的”道歉太有限了。

当我找到有关此的更多信息时,我会更新此答案。


我不确定我们能否在下一个 beta(或 GM 或 Released 版本...)中看到这种行为,但这在 Xcode 8 beta 6 中可以正常工作。

let foo: Any = 4
if type(of: foo) is AnyClass {
    print("It's an object.")
    let object = foo as AnyObject
    //do something with `object` that requires reference semantics
} else {
    print("It's not an object.") //->It's not an object.
}

class MyClass {}
let bar: Any = MyClass()
if type(of: bar) is AnyClass {
    print("It's an object.") //->It's an object.
    let object = foo as AnyObject
    //do something with `object` that requires reference semantics
} else {
    print("It's not an object.")
}

let baz: Any = Array<AnyObject>()
if type(of: baz) is AnyClass {
    print("It's an object.")
    let object = foo as AnyObject
    //do something with `object` that requires reference semantics
} else {
    print("It's not an object.") //->It's not an object.
}

我无法检查所有可能的情况,因此可能有一些边缘情况不起作用。但据我测试,这似乎按预期工作。

【讨论】:

  • 请注意,从 Swift 3.0 开始,当采用存在类型时,这会破坏优化的发布版本:bugs.swift.org/browse/SR-2867
  • @PaulCantrell,感谢您的报告。我会更新我的答案,包括该信息。
  • 这在 Xcode 8.3.3 中运行没有问题,包括调试和发布版本。
【解决方案2】:

也许您想查看Mirror,它可以进行一定程度的内省。文档是here

import Foundation

func prettyPrint(_ any: Any) -> String {
    let m = Mirror(reflecting: any)
    switch m.displayStyle {
    case .some(.class): // ****
        return "Class"
    case .some(.collection):
        return "Collection, \(m.children.count) elements"
    case .some(.tuple):
        return "Tuple, \(m.children.count) elements"
    case .some(.dictionary):
        return "Dictionary, \(m.children.count) elements"
    case .some(.set):
        return "Set, \(m.children.count) elements"
    case .some(.optional):
        return "Optional"
    case .some(.enum):
        return "Enum"
    case .some(.struct):
        return "Struct"
    default:
        return "\(String(describing: m.displayStyle))"
    }
}
class A {}

prettyPrint([1, 2, 3]) // "Collection, 3 elements"
prettyPrint(Set<String>()) // "Set, 0 elements"
prettyPrint([1: 2, 3: 4]) // "Dictionary, 2 elements"
prettyPrint((1, 2, 3)) // "Tuple, 3 elements"
prettyPrint(3) // "nil"
prettyPrint("3") // "nil"
prettyPrint(NSObject()) // "Class"
prettyPrint(NSArray(array:[1, 2, 3])) // "Collection, 3 elements"
prettyPrint(A()) // "Class"

// prettyPrint(nil) // Compile time error "Nil is not compatible with Any

【讨论】:

    猜你喜欢
    • 2011-05-16
    • 2015-02-22
    • 1970-01-01
    • 2017-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-02
    相关资源
    最近更新 更多