在Swift中检查对象是否为给定类型


267

我有一个由组成的数组AnyObject。我想对其进行迭代,并找到所有属于数组实例的元素。

如何在Swift中检查对象是否为给定类型?


您的问题询问有关查找给定对象的类型的问题,但是您已经接受了只能检查对象是否属于给定类型的答案。我建议您将问题具体编辑为这样,否则许多读者将对您接受的答案不满意。(所有其他答案都是相似的,因此幸运的是,您不必担心缩小问题范围而使它们无效。)
Jeremy Banks

我已经编辑了该问题,以使它与stackoverflow.com/q/24093433的歧义相符,我正投票决定重新开放该问题。它们都是有用的,相似的问题,但是答案是完全不同的,因此将它们分开是很有用的。
杰里米·班克斯

Answers:


304

如果要检查特定类型,可以执行以下操作:

if let stringArray = obj as? [String] {
    // obj is a string array. Do something with stringArray
}
else {
    // obj is not a string array
}

您可以使用“ as!” 如果obj类型不正确,则会引发运行时错误[String]

let stringArray = obj as! [String]

您也可以一次检查一个元素:

let items : [Any] = ["Hello", "World"]
for obj in items {
   if let str = obj as? String {
      // obj is a String. Do something with str
   }
   else {
      // obj is not a String
   }
}

?不存在时为什么只抛出运行时错误而不抛出编译时错误?这听起来像as?组合时将执行运行时检查。当可适当使用as??提前致谢。
Unheilig 2014年

@Unheilig您应该只使用as未经?如果没有这样你的程序可以从对象不是那种类型的,因为该计划将立即停止,如果它是无法恢复。使用?if语句让程序继续。
drewag

感谢您的回复。如果我错了,请纠正我:我认为?在这种情况下使用if将对if子句进行“泛型”类型检查,如果不是,则对else子句进行类型检查。如果没有?else,则永远不会输入,并且如您所指出的那样会导致运行时错误。再次感谢。
Unheilig 2014年

@Unheilig对不起,我不明白您在说什么/问什么。在?允许分配返回nil引起if语句来回报false,因此通过对else语句下降。但是,我认为解释有助于理解,但if let实际上是编译器中的一种特殊情况
drewag 2014年

1
@Unheilig正确,如果您希望能够在该本地范围内修改值,则可以使用var(这些更改不会影响范围之外)
drewag 2014年

202

Swift 2.2-5中,您现在可以执行以下操作:

if object is String
{
}

然后过滤您的数组:

let filteredArray = originalArray.filter({ $0 is Array })

如果要检查多种类型:

    switch object
    {
    case is String:
        ...

    case is OtherClass:
        ...

    default:
        ...
    }

这个解决方案虽然较短,但是却有一个缺点:您不能将object用作String括号内(至少在Swift 2中),而使用let解决方案则可以。
Ferran Maylinch '17

@FerranMaylinch无法理解您的意思,因为object在代码块中使用就可以了。
含义-

@含义-例如,object.uppercaseString由于变量的类型未强制转换为该类型,您将无法执行操作,您只是检查了对象(由变量指向)是String
Ferran Maylinch

如果您要检查的类类型是任意的,该怎么办?如果只有变量,则需要从中获取类类型?
Alex Zavatone

152

如果您只想知道对象是否是给定类型的子类型,则有一种更简单的方法:

class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}

func area (shape: Shape) -> Double {
  if shape is Circle { ... }
  else if shape is Rectangle { ... }
}

“使用类型检查运算符(is)检查实例是否属于某个子类类型。如果实例属于该子类类型,则类型检查运算符返回true,否则返回false。” 摘录自:苹果公司“ The Swift Programming Language”。iBooks

在上面,短语“某种子类类型”很重要。使用is Circleis Rectangle由编译器,因为该值接受shape被声明为Shape(类的超类CircleRectangle)。

如果您使用基本类型,则超类为Any。这是一个例子:

 21> func test (obj:Any) -> String {
 22.     if obj is Int { return "Int" }
 23.     else if obj is String { return "String" }
 24.     else { return "Any" }
 25. } 
 ...  
 30> test (1)
$R16: String = "Int"
 31> test ("abc")
$R17: String = "String"
 32> test (nil)
$R18: String = "Any"

2
如果我将原始类型存储在数组中或该数组是原始类型之一,该is怎么办在这里仍然可以呢?谢谢。
Unheilig 2014年

如果将objectas 声明为,它应该可以工作Any。更新了一个示例。
GoZoner 2014年

谢谢您的回复。看起来很有希望。我唯一的疑问是,根据以下AnyObject建议的答案,由于AnyObject未继承自,因此似乎已被驳回NSObject。如果Any不同,那么实际上这也是一个很好的解决方案。谢谢。
Unheilig 2014年

21

我有2种方法:

if let thisShape = aShape as? Square 

要么:

aShape.isKindOfClass(Square)

这是一个详细的示例:

class Shape { }
class Square: Shape { } 
class Circle: Shape { }

var aShape = Shape()
aShape = Square()

if let thisShape = aShape as? Square {
    println("Its a square")
} else {
    println("Its not a square")
}

if aShape.isKindOfClass(Square) {
    println("Its a square")
} else {
    println("Its not a square")
}

编辑:3现在:

let myShape = Shape()
if myShape is Shape {
    print("yes it is")
}

1
isKindOfClass是该NSObject协议的一种方法;它仅适用于采用它的类(所有类均源自NSObject,以及任何明确采用它的自定义Swift类)
Nicolas Miari


9

假设drawTriangle是UIView的实例。要检查drawTriangle是否为UITableView类型:

Swift 3中

if drawTriangle is UITableView{
    // in deed drawTriangle is UIView
    // do something here...
} else{
    // do something here...
}

这也可以用于您自己定义的类。您可以使用它来检查视图的子视图。


5

为什么不使用专门为此任务构建的内置功能?

let myArray: [Any] = ["easy", "as", "that"]
let type = type(of: myArray)

Result: "Array<Any>"

type()函数非常简单
:)

5

请注意以下事项:

var string = "Hello" as NSString
var obj1:AnyObject = string
var obj2:NSObject = string

print(obj1 is NSString)
print(obj2 is NSString)
print(obj1 is String)
print(obj2 is String) 

最后四行都返回true,这是因为如果您键入

var r1:CGRect = CGRect()
print(r1 is String)

...当然会显示“ false”,但警告消息说从CGRect转换为String失败。因此,某些类型被桥接,ans“ is”关键字称为隐式转换。

您最好使用以下之一:

myObject.isKind(of: MyClass.self)) 
myObject.isMember(of: MyClass.self))

2

如果由于未使用定义的值而只想检查该类而没有警告(请让someVariable ...),则可以简单地将let替换为布尔值:

if (yourObject as? ClassToCompareWith) != nil {
   // do what you have to do
}
else {
   // do something else
}

当我使用让步方式而不使用定义的值时,Xcode提出了此建议。


2

为什么不使用这样的东西

fileprivate enum types {
    case typeString
    case typeInt
    case typeDouble
    case typeUnknown
}

fileprivate func typeOfAny(variable: Any) -> types {
    if variable is String {return types.typeString}
    if variable is Int {return types.typeInt}
    if variable is Double {return types.typeDouble}
    return types.typeUnknown
}

在Swift 3中


2

Swift 4.2,就我而言,使用isKind函数。

isKind(of :)返回一个布尔值,该值指示接收方是给定类的实例还是从该类继承的任何类的实例。

  let items : [AnyObject] = ["A", "B" , ... ]
  for obj in items {
    if(obj.isKind(of: NSString.self)){
      print("String")
    }
  }

阅读更多https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418511-iskind


1
那不是Swift。它是可可粉,并且仅在适用于目标C的地方起作用
。– matt

1

myObject as? Stringnil如果myObject不是,则返回String。否则,它将返回一个String?,因此您可以使用来访问字符串本身myObject!,也可以使用进行myObject! as String安全地转换。


1

斯威夫特3:

class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}

if aShape.isKind(of: Circle.self) {
}

1

只是为了基于接受的答案和其他一些内容的完整性:

let items : [Any] = ["Hello", "World", 1]

for obj in items where obj is String {
   // obj is a String. Do something with str
}

但是,您也可以(compactMap也可以“映射”没有的值filter):

items.compactMap { $0 as? String }.forEach{ /* do something with $0 */ ) }

和使用的版本switch

for obj in items {
    switch (obj) {
        case is Int:
           // it's an integer
        case let stringObj as String:
           // you can do something with stringObj which is a String
        default:
           print("\(type(of: obj))") // get the type
    }
}

但是,坚持这个问题,检查它是否是一个数组(即[String]):

let items : [Any] = ["Hello", "World", 1, ["Hello", "World", "of", "Arrays"]]

for obj in items {
  if let stringArray = obj as? [String] {
    print("\(stringArray)")
  }
}

或更笼统(请参阅此其他问题的答案):

for obj in items {
  if obj is [Any] {
    print("is [Any]")
  }

  if obj is [AnyObject] {
    print("is [AnyObject]")
  }

  if obj is NSArray {
    print("is NSArray")
  }
}

1

as?不会总是给您预期的结果,因为as它不会测试数据类型是否为特定种类,而是仅在数据类型可以转换为表示为特定种类时才进行测试。

考虑以下代码,例如:

func handleError ( error: Error ) {
    if let nsError = error as? NSError {

符合Error协议的每种数据类型都可以转换为NSError对象,因此这将始终成功。但这并不意味着它error实际上是NSError对象或对象的子类。

正确的类型检查将是:

func handleError ( error: Error ) {
    if type(of: error) == NSError.self {

但是,这仅检查确切的类型。如果您还想包含的子类NSError,则应使用:

func handleError ( error: Error ) {
    if error is NSError.Type {

0

如果您有这样的回应:

{
  "registeration_method": "email",
  "is_stucked": true,
  "individual": {
    "id": 24099,
    "first_name": "ahmad",
    "last_name": "zozoz",
    "email": null,
    "mobile_number": null,
    "confirmed": false,
    "avatar": "http://abc-abc-xyz.amazonaws.com/images/placeholder-profile.png",
    "doctor_request_status": 0
  },
  "max_number_of_confirmation_trials": 4,
  "max_number_of_invalid_confirmation_trials": 12
}

并且您想要检查is_stucked将被读取为AnyObject的值,您所要做的就是

if let isStucked = response["is_stucked"] as? Bool{
  if isStucked{
      print("is Stucked")
  }
  else{
      print("Not Stucked")
 }
}

0

如果您不知道从服务器的响应中将得到字典或单个词典的数组,则需要检查结果是否包含数组。
就我而言,除一次外,总是收到一系列字典。因此,为了解决这个问题,我将以下代码用于swift 3。

if let str = strDict["item"] as? Array<Any>

在这里吗?Array检查获得的值是否为(字典项的)数组。在其他情况下,您可以处理是否为单个字典项而不是保留在数组中。


0

Swift 5.2 Xcode版本:11.3.1(11C504)

这是我检查数据类型的解决方案:

 if let typeCheck = myResult as? [String : Any] {
        print("It's Dictionary.")
    } else { 
        print("It's not Dictionary.") 
    }

希望对您有帮助。


当回答一个旧问题时,如果您包含一些上下文来解释您的答案有什么帮助,特别是对于已经接受了答案的问题,那么对于其他StackOverflow用户而言,您的答案将更加有用。请参阅:如何写一个好的答案
David Buck
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.