Arrays 斯威夫特:有什么东西吗?如果数组为空(不是零),则数组强制转换失败

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

情况就是这样:假设我得到一个变量作为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"

这表明对于空数组,强制转换失败。那么,有没有办法解决这个问题呢?

这样的代码强烈地暗示了类型设计中的一个深层次问题,应该通过去掉任何对象来解决。传递
AnyObject
是正确的工具,这是非常罕见的

你在这里说了一些非常重要的话:

如果接收的对象不是空数组(非nil),则此代码有效

空数组与
nil
不同。如果您通过
nil
,则这是可选的<代码>可选
[Cat]
不同,您不应该期望它始终
为?
强制转换,特别是如果它是
。如果这个值来自ObjC,那么
nil
将桥接到实际的Obj-C
nil
(这只是值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"
)