Tengo una matriz compuesta de AnyObject
. Quiero iterar sobre él y encontrar todos los elementos que son instancias de matriz.
¿Cómo puedo verificar si un objeto es de un tipo dado en Swift?
Tengo una matriz compuesta de AnyObject
. Quiero iterar sobre él y encontrar todos los elementos que son instancias de matriz.
¿Cómo puedo verificar si un objeto es de un tipo dado en Swift?
Respuestas:
Si desea verificar un tipo específico, puede hacer lo siguiente:
if let stringArray = obj as? [String] {
// obj is a string array. Do something with stringArray
}
else {
// obj is not a string array
}
Puedes usar "como!" y eso arrojará un error de tiempo de ejecución si obj
no es de tipo[String]
let stringArray = obj as! [String]
También puede verificar un elemento a la vez:
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
}
}
?
no está presente? Suena como as
y ?
cuando se combina realizará una verificación de tiempo de ejecución. ¿Cuándo sería apropiado usar as
sin ?
? Gracias por adelantado.
as
sin el ?
si no hay forma de que su programa pueda recuperarse del objeto que no es de ese tipo porque el programa se detendrá inmediatamente si no lo es. El uso de ?
en la if
declaración permite que el programa continúe.
?
en este caso realizaría una verificación de tipo "genérico", en caso afirmativo, a la cláusula if, si no, a la cláusula else. Sin lo ?
contrario, nunca se ingresaría y, como señaló, provocará un error de tiempo de ejecución. Gracias de nuevo.
?
permite la asignación para volver nil
haciendo que la sentencia if para el retorno false
y, por tanto, que cae a través de la sentencia else. Sin embargo, creo que la explicación ayuda con el entendimiento, pero if let
en realidad es un caso especial en el compilador
En Swift 2.2 - 5 ahora puede hacer:
if object is String
{
}
Luego, para filtrar su matriz:
let filteredArray = originalArray.filter({ $0 is Array })
Si tiene varios tipos para verificar:
switch object
{
case is String:
...
case is OtherClass:
...
default:
...
}
object
como String
dentro de las llaves (al menos en Swift 2), mientras que con la let
solución puede hacerlo.
object
en el bloque está bien.
object.uppercaseString
porque el tipo de la variable no está fundido a ese tipo, simplemente verificó que el objeto (señalado por la variable) es unString
Si solo desea saber si un objeto es un subtipo de un tipo dado, entonces hay un enfoque más simple:
class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}
func area (shape: Shape) -> Double {
if shape is Circle { ... }
else if shape is Rectangle { ... }
}
“Utilice el operador de verificación de tipo (is) para verificar si una instancia es de cierto tipo de subclase. El operador de verificación de tipo devuelve verdadero si la instancia es de ese tipo de subclase y falso si no lo es ". Extracto de: Apple Inc. "El lenguaje de programación Swift". iBooks .
En lo anterior, la frase 'de cierto tipo de subclase' es importante. El compilador acepta el uso de is Circle
y is Rectangle
porque ese valor shape
se declara como Shape
(una superclase de Circle
y Rectangle
).
Si está utilizando tipos primitivos, la superclase sería Any
. Aquí hay un ejemplo:
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
todavía funcionaría aquí? Gracias.
object
como Any
. Actualizado con un ejemplo.
AnyObject
se sugiere, parece haber sido replicada debido a que AnyObject
no heredó de NSObject
. Si Any
es diferente, entonces esta sería una gran solución también. Gracias.
Tengo 2 formas de hacerlo:
if let thisShape = aShape as? Square
O:
aShape.isKindOfClass(Square)
Aquí hay un ejemplo detallado:
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")
}
Editar: 3 ahora:
let myShape = Shape()
if myShape is Shape {
print("yes it is")
}
isKindOfClass
es un método del NSObject
protocolo; solo debería funcionar para las clases que lo adoptan (todas las clases que descienden de NSObject, más cualquier clase personalizada de Swift que lo adopte explícitamente)
para swift4:
if obj is MyClass{
// then object type is MyClass Type
}
Asumir dibujar Triángulo es una instancia de UIView. Para verificar si drawTriangle es del tipo UITableView:
En Swift 3 ,
if drawTriangle is UITableView{
// in deed drawTriangle is UIView
// do something here...
} else{
// do something here...
}
Esto también podría usarse para clases definidas por usted mismo. Puede usar esto para verificar las subvistas de una vista.
¿Por qué no utilizar la funcionalidad integrada creada especialmente para esta tarea?
let myArray: [Any] = ["easy", "as", "that"]
let type = type(of: myArray)
Result: "Array<Any>"
Ten cuidado con esto:
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)
Las cuatro últimas líneas devuelven verdadero, esto se debe a que si escribe
var r1:CGRect = CGRect()
print(r1 is String)
... imprime "falso", por supuesto, pero una Advertencia dice que falla la transmisión de CGRect a String. Por lo tanto, se conectan algunos tipos, y la palabra clave 'is' llama un molde implícito.
Deberías usar uno de estos:
myObject.isKind(of: MyClass.self))
myObject.isMember(of: MyClass.self))
Si solo desea verificar la clase sin recibir una advertencia debido al valor definido no utilizado (let someVariable ...), simplemente puede reemplazar el material let con un valor booleano:
if (yourObject as? ClassToCompareWith) != nil {
// do what you have to do
}
else {
// do something else
}
Xcode propuso esto cuando utilicé let way y no utilicé el valor definido.
¿Por qué no usar algo como esto?
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
}
en Swift 3.
Swift 4.2, en mi caso, usando la función isKind.
isKind (of :) Devuelve un valor booleano que indica si el receptor es una instancia de una clase dada o una instancia de cualquier clase que herede de esa clase.
let items : [AnyObject] = ["A", "B" , ... ]
for obj in items {
if(obj.isKind(of: NSString.self)){
print("String")
}
}
Leer más https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418511-iskind
Solo en aras de la exhaustividad basada en la respuesta aceptada y algunas otras:
let items : [Any] = ["Hello", "World", 1]
for obj in items where obj is String {
// obj is a String. Do something with str
}
Pero también puede ( compactMap
también "asigna" los valores que filter
no):
items.compactMap { $0 as? String }.forEach{ /* do something with $0 */ ) }
Y una versión usando 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
}
}
Pero atendiendo a la pregunta, para verificar si es una matriz (es decir [String]
):
let items : [Any] = ["Hello", "World", 1, ["Hello", "World", "of", "Arrays"]]
for obj in items {
if let stringArray = obj as? [String] {
print("\(stringArray)")
}
}
O de manera más general (vea esta otra pregunta respuesta )
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?
no siempre le dará el resultado esperado porque as
no prueba si un tipo de datos es de un tipo específico, sino solo si un tipo de datos se puede convertir o representar como un tipo específico.
Considere este código, por ejemplo:
func handleError ( error: Error ) {
if let nsError = error as? NSError {
Cada tipo de datos conforme al Error
protocolo se puede convertir en un NSError
objeto, por lo que esto siempre tendrá éxito . Sin embargo, eso no significa que error
de hecho sea un NSError
objeto o una subclase de él.
Una verificación de tipo correcta sería:
func handleError ( error: Error ) {
if type(of: error) == NSError.self {
Sin embargo, esto verifica solo el tipo exacto. Si desea incluir también la subclase de NSError
, debe usar:
func handleError ( error: Error ) {
if error is NSError.Type {
Si tiene una respuesta como esta:
{
"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
}
y desea verificar el valor is_stucked
que se leerá como AnyObject, todo lo que tiene que hacer es esto
if let isStucked = response["is_stucked"] as? Bool{
if isStucked{
print("is Stucked")
}
else{
print("Not Stucked")
}
}
Si no sabe que obtendrá una matriz de diccionarios o un solo diccionario en la respuesta del servidor, debe verificar si el resultado contiene una matriz o no.
En mi caso, siempre recibo una serie de diccionarios, excepto una vez. Entonces, para manejar eso, utilicé el siguiente código para Swift 3.
if let str = strDict["item"] as? Array<Any>
¿Aquí como? La matriz verifica si el valor obtenido es matriz (de elementos del diccionario). En otro caso, puede manejar si es un elemento de diccionario único que no se mantiene dentro de una matriz.
Swift 5.2 y Versión Xcode: 11.3.1 (11C504)
Aquí está mi solución de verificar el tipo de datos:
if let typeCheck = myResult as? [String : Any] {
print("It's Dictionary.")
} else {
print("It's not Dictionary.")
}
Espero que te ayude.