Ho un array composto da AnyObject
. Voglio iterare su di esso e trovare tutti gli elementi che sono istanze di array.
Come posso verificare se un oggetto è di un determinato tipo in Swift?
Ho un array composto da AnyObject
. Voglio iterare su di esso e trovare tutti gli elementi che sono istanze di array.
Come posso verificare se un oggetto è di un determinato tipo in Swift?
Risposte:
Se si desidera verificare un tipo specifico, è possibile effettuare le seguenti operazioni:
if let stringArray = obj as? [String] {
// obj is a string array. Do something with stringArray
}
else {
// obj is not a string array
}
Puoi usare "as!" e questo genererà un errore di runtime se obj
non è di tipo[String]
let stringArray = obj as! [String]
Puoi anche controllare un elemento alla volta:
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
}
}
?
non è presente. Sembra che as
e ?
quando combinato eseguirà il controllo di runtime. Quando sarebbe appropriato usare as
senza ?
? Grazie in anticipo.
as
senza la ?
se non v'è alcun modo il vostro programma potrebbe recuperare dall'oggetto non essere di quel tipo perché il programma immediatamente fermare se non lo è. L'uso di ?
in if
nell'istruzione consente al programma di continuare.
?
in questo caso avrebbe eseguito un controllo di tipo "generico", in caso affermativo, alla clausola if, in caso contrario, alla clausola else. Senza l' ?
altro non verrebbe mai inserito e come hai sottolineato causerebbe un errore di runtime. Grazie ancora.
?
consente di restituire l'assegnazione nil
causando la restituzione dell'istruzione if false
e quindi la restituzione dell'istruzione else. Tuttavia, penso che questa spiegazione sia di aiuto nella comprensione, ma in if let
realtà è un caso speciale nel compilatore
In Swift 2.2 - 5 ora puoi fare:
if object is String
{
}
Quindi per filtrare l'array:
let filteredArray = originalArray.filter({ $0 is Array })
Se hai più tipi da controllare:
switch object
{
case is String:
...
case is OtherClass:
...
default:
...
}
object
come String
all'interno delle parentesi graffe (almeno in Swift 2), mentre con la let
soluzione è possibile farlo.
object
nel blocco va bene.
object.uppercaseString
perché il tipo della variabile non viene trasmesso a quel tipo, hai appena verificato che l'oggetto (puntato dalla variabile) sia unString
Se vuoi solo sapere se un oggetto è un sottotipo di un determinato tipo, esiste un approccio più semplice:
class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}
func area (shape: Shape) -> Double {
if shape is Circle { ... }
else if shape is Rectangle { ... }
}
"Utilizzare l'operatore di verifica del tipo (is) per verificare se un'istanza è di un determinato tipo di sottoclasse. L'operatore di verifica del tipo restituisce true se l'istanza è di quel tipo di sottoclasse e false se non lo è. " Estratto da: Apple Inc. "The Swift Programming Language".iBooks .
In quanto sopra è importante la frase "di un certo tipo di sottoclasse". L'uso di is Circle
e is Rectangle
è accettato dal compilatore perché quel valore shape
è dichiarato come Shape
(una superclasse di Circle
eRectangle
).
Se stai usando tipi primitivi, la superclasse sarebbe Any
. Ecco un esempio:
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
funzionerebbe ancora qui? Grazie.
object
as Any
. Aggiornato con un esempio.
AnyObject
viene suggerito, sembra essere stato replicato a causa della AnyObject
non ereditarietà NSObject
. Se Any
è diverso, allora in realtà sarebbe anche un'ottima soluzione. Grazie.
Ho 2 modi per farlo:
if let thisShape = aShape as? Square
O:
aShape.isKindOfClass(Square)
Ecco un esempio dettagliato:
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")
}
Modifica: 3 ora:
let myShape = Shape()
if myShape is Shape {
print("yes it is")
}
isKindOfClass
è un metodo del NSObject
protocollo; dovrebbe funzionare solo per le classi che lo adottano (tutte le classi discendenti da NSObject, oltre a qualsiasi classe Swift personalizzata che lo adotti esplicitamente)
per swift4:
if obj is MyClass{
// then object type is MyClass Type
}
Assumi drawTriangle sia un'istanza di UIView. Per verificare se drawTriangle è di tipo UITableView:
In Swift 3 ,
if drawTriangle is UITableView{
// in deed drawTriangle is UIView
// do something here...
} else{
// do something here...
}
Questo potrebbe anche essere usato per le classi definite da te. Puoi usarlo per controllare le viste secondarie di una vista.
Perché non utilizzare la funzionalità integrata creata appositamente per questa attività?
let myArray: [Any] = ["easy", "as", "that"]
let type = type(of: myArray)
Result: "Array<Any>"
Attenzione:
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)
Tutte e quattro le ultime righe restituiscono true, questo perché se digiti
var r1:CGRect = CGRect()
print(r1 is String)
... stampa "falso" ovviamente, ma un avvertimento dice che il Cast da CGRect a String fallisce. Quindi alcuni tipi sono collegati a ponte, e la parola chiave "is" chiama un cast implicito.
Dovresti usare uno di questi:
myObject.isKind(of: MyClass.self))
myObject.isMember(of: MyClass.self))
Se vuoi solo controllare la classe senza ricevere un avviso a causa del valore definito inutilizzato (let someVariable ...), puoi semplicemente sostituire le cose let con un valore booleano:
if (yourObject as? ClassToCompareWith) != nil {
// do what you have to do
}
else {
// do something else
}
Xcode lo ha proposto quando ho usato il modo let e non ho usato il valore definito.
Perché non usare qualcosa del genere
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
}
in Swift 3.
Swift 4.2, Nel mio caso, usando la funzione isKind.
isKind (of :) Restituisce un valore booleano che indica se il destinatario è un'istanza di una determinata classe o un'istanza di qualsiasi classe che eredita da quella classe.
let items : [AnyObject] = ["A", "B" , ... ]
for obj in items {
if(obj.isKind(of: NSString.self)){
print("String")
}
}
Leggi di più https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418511-iskind
Solo per completezza basata sulla risposta accettata e su alcuni altri:
let items : [Any] = ["Hello", "World", 1]
for obj in items where obj is String {
// obj is a String. Do something with str
}
Ma puoi anche ( compactMap
anche "mappare" i valori che filter
non lo fanno):
items.compactMap { $0 as? String }.forEach{ /* do something with $0 */ ) }
E una versione che utilizza 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
}
}
Ma attenendosi alla domanda, per verificare se si tratta di un array (cioè [String]
):
let items : [Any] = ["Hello", "World", 1, ["Hello", "World", "of", "Arrays"]]
for obj in items {
if let stringArray = obj as? [String] {
print("\(stringArray)")
}
}
O più in generale (vedi questa altra risposta alla domanda ):
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?
non ti darà sempre il risultato atteso perché as
non verifica se un tipo di dati è di un tipo specifico ma solo se un tipo di dati può essere convertito o rappresentato come tipo specifico.
Considera questo codice per esempio:
func handleError ( error: Error ) {
if let nsError = error as? NSError {
Ogni tipo di dati conforme al Error
protocollo può essere convertito in un NSError
oggetto, quindi ciò avrà sempre successo . Tuttavia ciò non significa che error
in realtà sia un NSError
oggetto o una sua sottoclasse.
Un controllo del tipo corretto sarebbe:
func handleError ( error: Error ) {
if type(of: error) == NSError.self {
Tuttavia, questo controlla solo il tipo esatto. Se si desidera includere anche la sottoclasse di NSError
, è necessario utilizzare:
func handleError ( error: Error ) {
if error is NSError.Type {
Se hai una risposta come questa:
{
"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
}
e vuoi verificare il valore is_stucked
che verrà letto come AnyObject, tutto ciò che devi fare è questo
if let isStucked = response["is_stucked"] as? Bool{
if isStucked{
print("is Stucked")
}
else{
print("Not Stucked")
}
}
Se non sai che otterrai una matrice di dizionari o un singolo dizionario nella risposta dal server devi controllare se il risultato contiene una matrice o meno.
Nel mio caso ricevo sempre una serie di dizionari tranne una volta. Quindi, per gestirlo ho usato il codice seguente per swift 3.
if let str = strDict["item"] as? Array<Any>
Qui come? Array controlla se il valore ottenuto è array (di voci del dizionario). In caso contrario, è possibile gestire se si tratta di un singolo elemento del dizionario che non viene conservato in un array.
Swift 5.2 e versione Xcode: 11.3.1 (11C504)
Ecco la mia soluzione di controllo del tipo di dati:
if let typeCheck = myResult as? [String : Any] {
print("It's Dictionary.")
} else {
print("It's not Dictionary.")
}
Spero che ti possa aiutare.