Arrays 斯威夫特:有什么东西吗?如果数组为空(不是零),则数组强制转换失败
情况就是这样:假设我得到一个变量作为AnyObject或Any。然后,我必须强制转换变量,以确定它是否是一个包含特定类型对象的数组Arrays 斯威夫特:有什么东西吗?如果数组为空(不是零),则数组强制转换失败,arrays,swift,casting,Arrays,Swift,Casting,情况就是这样:假设我得到一个变量作为AnyObject或Any。然后,我必须强制转换变量,以确定它是否是一个包含特定类型对象的数组 func myFuction(receivedObject: AnyObject) { if let validDogs = receivedObject as? [Dog] { print("Received object is an array of dogs") // Do something with valid d
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"
这表明对于空数组,强制转换失败。那么,有没有办法解决这个问题呢?这样的代码强烈地暗示了类型设计中的一个深层次问题,应该通过去掉
任何对象来解决。传递AnyObject
是正确的工具,这是非常罕见的
你在这里说了一些非常重要的话:
如果接收的对象不是空数组(非nil),则此代码有效
空数组与nil
不同。如果您通过nil
,则这是可选的<代码>可选
与[Cat]
不同,您不应该期望它始终为?
强制转换,特别是如果它是零
。如果这个值来自ObjC,那么nil
将桥接到实际的Obj-Cnil
(这只是值0),并且运行时实际上没有什么可处理的
你说你收到了两行日志。这表明两个转换都是成功的,而不是失败的。如果是这种情况,我假设这是一个NSArray
,空的NSArray
可以合法地被转换为任何数组(NSArray
内部没有元素类型)。因此,上述情况是可以预料的
如果它确实是可选的,那么对于“如何确定它是可选的,然后打开它,然后确定它是否是[Cat]
”的问题,答案是“停止;您对AnyObject
做得太过分了”,首先重新设计它,这样您就不需要它,这通常意味着要更早地确定您的类型
执行您尝试执行的操作的正确方法通常是使用重载,而不是as?
casting:
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
剥离类型,这表明您确实已经知道这些类型,并且正在积极地丢弃它们,并尝试稍后恢复它们。如果是这种情况,则上述代码正是正确的。不要丢弃这些类型。)
虽然在某些情况下,您无法了解这些类型(因为您实际上接受的是“任何对象”),在绝大多数情况下,不了解您的类型表明存在设计问题。@RobNapier的答案从良好的编程角度来看是正确的-我看不出有任何理由做您正在尝试的事情,但它显示出一些有趣的东西
首先,不能用任何数组调用函数-数组,如struct
s,不符合AnyObject
(类是这样的)。但是,您可以通过强制强制强制转换来调用该函数,因为任何东西都可以被强制转换为任何对象(可能是通过将结构包装在退化类中),因此调用是编译的
其次,您的问题的推论是错误的-您说“这表明对于空数组,强制转换失败。”-并非如此,强制转换在两种情况下都成功
让我们看看到底传递了什么:
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]
试一试
这张照片
myFuction called with (
"__lldb_expr_107.Cat",
"__lldb_expr_107.Dog"
)
(并且不打印演员阵容“成功”)
长短不一
A) 原力as!任何对象
都会有效地丢弃数组类型,并传递类似于元素元组的内容,而您的let\uas?
能够从元素类型重新组合到数组中
B) 重新阅读@RobNapier的答案——这就是出路 我看不出如何将任何内容的数组作为AnyObject
传递,因为数组是一个结构,而不是一个类。当然,除非它是一个NSArray
。告诉我们你怎么称呼它。嗨@Grimxn。请参阅:self.myfunction(receivedObject:object as!AnyObject)
好的,但是如果不强制它,就不能传入,比如说,[Cat()]
-它不编译。好的,它在这里编译。我使用的是Xcode 8.3.3,为了清楚起见,我的意思是你不能调用MyFunction(receivedObject:[Cat()])
-至少在Xcode 9.1中不能。。。您可以调用myFuction(receivedObject:[Cat()]as!AnyObject)
myFuction called with (
"__lldb_expr_107.Cat",
"__lldb_expr_107.Dog"
)