【问题标题】:Checking if an object is a given type in Swift检查对象是否是 Swift 中的给定类型
【发布时间】:2014-07-28 07:36:46
【问题描述】:

我有一个由AnyObject 组成的数组。我想遍历它,找到所有数组实例的元素。

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

【问题讨论】:

  • 您的问题涉及查找给定对象的类型,但您接受的答案只能检查对象是否属于给定类型。我建议您将您的问题具体编辑为,否则许多读者会对您接受的答案不满意。 (所有其他答案都是相似的,所以幸运的是,您不必担心通过缩小问题范围使它们无效。)
  • 我已经编辑了这个问题以消除它与stackoverflow.com/q/24093433 的歧义,我正在投票重新打开它。它们都是有用的、相似的问题,但答案却截然不同,因此将它们分开会很有用。

标签: swift type-inference typechecking


【解决方案1】:

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

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 如果您的程序无法从不属于该类型的对象中恢复,您应该只使用不带?as,因为如果不是,程序将立即停止。在if 语句中使用? 允许程序继续。
  • 感谢您的回复。如果我错了,请纠正我:我认为在这种情况下使用 ? 将对 if 子句执行“通用”类型检查,如果是,则对 else 子句执行。如果没有 ? else 将永远不会输入,并且正如您指出的那样会导致运行时错误。再次感谢。
  • @Unheilig 对不起,我不明白你在说什么/问什么。 ? 允许赋值返回 nil 导致 if 语句返回 false 并因此落入 else 语句。但是,我认为解释有助于理解,但if let实际上是编译器中的一个特例
  • @Unheilig 正确,如果您希望能够在该本地范围内修改值,则可以使用 var(这些更改不会影响范围之外)
【解决方案2】:

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解决方案你可以做到。
  • @FerranMaylinch 不明白你的意思,因为在块中使用object 很好。
  • @meaning-matters 例如您将无法执行object.uppercaseString,因为变量的类型未强制转换为该类型,您只需检查对象(由变量指向)是否为String
  • 如果你检查的类类型是任意的,你怎么能做到这一点?如果你只有一个变量,你需要从中获取一个类类型?
【解决方案3】:

如果你只想知道一个对象是否给定类型的子类型,那么有一个更简单的方法:

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。”摘自:Apple Inc.“Swift 编程语言”。 iBooks.

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

如果您使用原始类型,超类将是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"

【讨论】:

  • 如果我将原始类型存储在数组中,或者如果数组是原始类型之一,is 是否仍然可以在这里工作?谢谢。
  • 如果您将object 声明为Any,它应该可以工作。更新了一个例子。
  • 感谢您的回复。看起来很有希望。我唯一的疑问是,根据下面的答案,其中建议AnyObject,似乎由于AnyObject 没有从NSObject 继承而被反驳。如果Any 不同,那么这实际上也是一个很好的解决方案。谢谢。
【解决方案4】:

我有两种方法:

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")
}

【讨论】:

  • isKindOfClassNSObject 协议的一个方法;它应该只适用于采用它的类(所有继承自 NSObject 的类,以及任何明确采用它的自定义 Swift 类)
【解决方案5】:

对于 swift4:

if obj is MyClass{
    // then object type is MyClass Type
}

【讨论】:

  • 最佳答案
【解决方案6】:

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

Swift 3 中,

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

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

【讨论】:

    【解决方案7】:

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

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

    【讨论】:

    • type() 函数很简单:)
    【解决方案8】:

    请注意:

    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 的转换失败。因此,某些类型被桥接,因为“is”关键字调用了隐式强制转换。

    您最好使用以下之一:

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

    【讨论】:

      【解决方案9】:

      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 {
      

      【讨论】:

        【解决方案10】:

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

        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)")
          }
        }
        

        或更笼统地说(见this other question answer):

        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")
          }
        }
        

        【讨论】:

          【解决方案11】:

          如果您只想检查类而不因为未使用的定义值(let someVariable ...)而收到警告,您可以简单地将 let 的东西替换为布尔值:

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

          Xcode 在我使用 let 方式并没有使用定义值时提出了这一点。

          【讨论】:

            【解决方案12】:

            为什么不使用这样的东西

            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 中。

            【讨论】:

              【解决方案13】:

              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

              【讨论】:

              • 那不是 Swift。它是 Cocoa 并且仅适用于适用于 Objective C 的地方。
              【解决方案14】:

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

              【讨论】:

                【解决方案15】:

                斯威夫特 3:

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

                【讨论】:

                  【解决方案16】:

                  如果你有这样的回应:

                  {
                    "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")
                   }
                  }
                  

                  【讨论】:

                    【解决方案17】:

                    如果您不知道您将在服务器的响应中获得字典数组或单个字典,则需要检查结果是否包含数组。
                    在我的情况下,总是收到一系列字典,除了一次。所以,为了处理这个问题,我使用了下面的 swift 3 代码。

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

                    在这里? Array 检查获取的值是否为(字典项的)数组。在其他情况下,如果它是未保存在数组中的单个字典项,您可以处理。

                    【讨论】:

                      【解决方案18】:

                      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 用户更有用,特别是对于已经有一个已接受答案的问题。请参阅:How do I write a good answer
                      【解决方案19】:
                      let originalArray : [Any?] = ["Hello", "World", 111, 2, nil, 3.34]
                      let strings = originalArray.compactMap({ $0 as? String })
                      
                      print(strings)
                      //printed: ["Hello", "World"]
                      

                      【讨论】:

                        【解决方案20】:

                        你可以使用这个函数,然后调用它

                         func printInfo(_ value: Any) {
                                let t = type(of: value)
                                print("'\(value)' of type '\(t)'")
                            }
                        

                        如 printInfo(data) “数据”类型的“125 字节”

                        【讨论】:

                        • 这个问题有 19 个 个现有答案,包括一个获得最高票数、超过 三百票 的被接受的答案。你确定你的解决方案还没有给出吗?如果是这样,您为什么认为您的方法改进了已被社区验证的现有提案?提供解释在 Stack Overflow 上总是 很有用,但在问题已得到解决且让 OP 和社区都满意的情况下,这一点尤其非常重要。通过解释您的答案的不同之处以及在什么情况下帮助未来的读者
                        猜你喜欢
                        • 2021-02-06
                        • 2017-12-06
                        • 2016-12-31
                        • 2011-09-26
                        • 2016-11-24
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多