Проверка, является ли объект заданным типом в Swift

У меня есть массив, который состоит из AnyObject, Я хочу перебрать его и найти все элементы, которые являются экземплярами массива.

Как я могу проверить, принадлежит ли объект заданному типу в Swift?

20 ответов

Решение

Если вы хотите проверить определенный тип, вы можете сделать следующее:

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

Вы можете использовать "как!" и это вызовет ошибку времени выполнения, если 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
   }
}

В Swift 2.2 - 4.0.3 теперь вы можете делать:

if object is String
{
}

Затем для фильтрации вашего массива:

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

Если вы хотите знать только, является ли объект подтипом данного типа, тогда есть более простой подход:

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 Circle а также is Rectangle принимается компилятором, потому что это значение shape объявлен как Shape (суперкласс Circle а также Rectangle).

Если вы используете примитивные типы, суперкласс будет 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"

для swift4:

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

У меня есть 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")
}

Предположим, что drawTriangle является экземпляром UIView.To проверить, имеет ли drawTriangle тип UITableView:

В Свифте 3

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

Это также может быть использовано для классов, определенных вами. Вы можете использовать это, чтобы проверить подпредставления представления.

Просто ради полноты на основе принятого ответа и некоторых других:

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

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 {

Почему бы не использовать встроенный функционал, созданный специально для этой задачи?

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

Result: "Array<Any>"

Будьте предупреждены об этом:

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)

... он печатает "ложь", конечно, но Предупреждение говорит о том, что приведение из CGRect к String завершается неудачно. Таким образом, некоторые типы являются мостовыми, а ключевое слово is вызывает неявное приведение.

Вы должны лучше использовать один из них:

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

Вы можете использовать эту функцию, а затем вызвать ее

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

например, printInfo(data) «125 байт» типа «Данные»

Почему бы не использовать что-то подобное

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
}

в Свифте 3.

Если вы просто хотите проверить класс без получения предупреждения из-за неиспользованного определенного значения (let someVariable ...), вы можете просто заменить let let на логическое значение:

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

Xcode предложил это, когда я использовал let way и не использовал определенное значение.

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

myObject as? String возвращается nil если myObject это не String, В противном случае он возвращает String?, так что вы можете получить доступ к самой строке с myObject!или с помощью myObject! as String безопасно.

Свифт 3:

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

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

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

Надеюсь, это вам поможет.

      let originalArray : [Any?] = ["Hello", "World", 111, 2, nil, 3.34]
let strings = originalArray.compactMap({ $0 as? String })

print(strings)
//printed: ["Hello", "World"]

Если вы не знаете, что в ответе от сервера вы получите массив словарей или отдельный словарь, вам нужно проверить, содержит ли результат массив или нет.
В моем случае всегда получаю массив словарей, кроме одного раза. Итак, чтобы справиться с этим, я использовал приведенный ниже код для Swift 3.

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

Вот как? Array проверяет, является ли полученное значение массивом (элементов словаря). В противном случае вы можете обработать, если это единственный элемент словаря, который не хранится внутри массива.

Если у вас есть ответ как этот:

{
  "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")
 }
}
Другие вопросы по тегам