情况就是这样:假设我得到一个变量为AnyObject或Any。然后,我必须转换变量以了解它是否是具有特定类型对象的数组。
func myFuction(receivedObject: AnyObject) {
if let validDogs = receivedObject as? [Dog] {
print("Received object is an array of dogs")
// Do something with valid dogs
}
if let validCats = receivedObject as? [Cat] {
print("Received object is an array of cats")
// Do something with valid cats
}
}
如果收到的对象不是空数组(不是nil),则此代码有效,但如果收到的对象是空数组则失败,因为我的日志打印了这两条消息:
"Received object is an array of dogs"
"Received object is an array of cats"
这表明对于空数组,强制转换失败。那么,有没有办法解决这个问题?
答案 0 :(得分:4)
这样的代码强烈暗示了你的类型设计中的一个深层次问题,应该通过删除AnyObject
来解决。传递AnyObject
是正确的工具非常罕见。
你在这里说了一些非常重要的事情:
如果接收的对象不是空数组(不是空)
,则此代码有效
空数组与nil
不同。如果您通过nil
,则该选项是可选的。 Optional<[Cat]>
与[Cat]
不同,您不应期望它始终as?
投射,特别是nil
nil
。如果这来自ObjC,那么nil
将桥接到一个实际的Obj-C as?
(它只是值0),并且运行时几乎无法使用。
但是你说你收到两个日志行。这表明两个NSArray
演员阵容都在成功,而不是失败。如果是这种情况,我认为这是NSArray
,空的as?
可以合法地NSArray
投射到任何数组([Cat]
没有元素类型内部)。所以上述情况是预期的。
如果它确实是可选的,那么问题是&#34;如何确定它是可选的然后打开它然后解决它是否AnyObject
&#34;答案是&#34;停止;你与as?
走得太远。&#34;首先重新设计这个,这样你就不需要了,这通常意味着更早地弄清楚你的类型。
执行您尝试做的事情的正确方法通常是重载,而不是func myFuction(receivedObject: [Dog]) {
print("Received object is an array of dogs")
// Do something with valid dogs
}
func myFuction(receivedObject: [Cat]) {
print("Received object is an array of cats")
// Do something with valid cats
}
施放:
AnyObject
您不能只将as! AnyObject
传递给上述功能。您需要知道您正在使用的事物的类型。 (您对Firestore
删除类型的评论表明您已经知道已经存在的类型,并且正在积极地抛弃这些类型并尝试稍后恢复它们。如果这是在这种情况下,上面的代码是完全正确的。不要丢弃类型。)
虽然有一些极端情况你无法知道这些类型(因为你真的在接受&#34;任何对象&#34;),在绝大多数情况下,不知道你的类型表明存在设计问题。
答案 1 :(得分:3)
首先,你不能用任何数组调用你的函数 - 数组,如struct
s,不符合AnyObject
(类做)。但是,你通过强制转换来调用函数 - 因为任何东西都可以转换为AnyObject(可能是通过将结构包装在简并类中),调用编译。
其次,你的问题推理是错误的 - 你说&#34;这表明对于一个空阵列,演员阵容失败。&#34; - 不是这样,演员在两个案件中成功 ......
让我们看看实际传入的内容:
class Pet { var name: String { return "" } }
class Dog: Pet { override var name: String { return "Fido" } }
class Cat: Pet { override var name: String { return "Cfor" } }
func myFuction(receivedObject: AnyObject) {
print("myFuction called with \(receivedObject)") // ***
if let validDogs = receivedObject as? [Dog] {
print("Received object is an array of dogs")
// Do something with valid dogs
}
if let validCats = receivedObject as? [Cat] {
print("Received object is an array of cats")
// Do something with valid cats
}
}
var a: [Cat] = [Cat()]
//myFuction(receivedObject: a) // Argument type '[Cat]' does not conform to expected type 'AnyObject'
myFuction(receivedObject: a as! AnyObject) // Forced cast from '[Cat]' to 'AnyObject' always succeeds; did you mean to use 'as'?
a = []
myFuction(receivedObject: a as! AnyObject) // Forced cast from '[Cat]' to 'AnyObject' always succeeds; did you mean to use 'as'?
输出:
myFuction called with (
"__lldb_expr_97.Cat"
)
Received object is an array of cats
myFuction called with (
)
Received object is an array of dogs
Received object is an array of cats
因此,当使用非空数组调用它时,类型是从成员推断的,如果成员属于正确的类型,则强制转换只会成功。空数组没有成员,因此同样可以是[Cat]
或[Dog]
或[String]
。
尝试
let b = [Cat(), Dog()]
myFuction(receivedObject: b as! AnyObject)
打印
myFuction called with (
"__lldb_expr_107.Cat",
"__lldb_expr_107.Dog"
)
(并且不打印演员&#34;成功&#34;)
它的长短是
A)力as! AnyObject
有效地抛弃了数组类型并传递了类似于元素元组的元素,您的let _ = as?
能够从类型中重新组合成一个数组元素。
B)重新阅读@ RobNapier的回答 - 这是要走的路!