Mam tablicę, która składa się z AnyObject
. Chcę iterować i znaleźć wszystkie elementy, które są instancjami tablicowymi.
Jak mogę sprawdzić, czy obiekt jest danego typu w Swift?
Mam tablicę, która składa się z AnyObject
. Chcę iterować i znaleźć wszystkie elementy, które są instancjami tablicowymi.
Jak mogę sprawdzić, czy obiekt jest danego typu w Swift?
Odpowiedzi:
Jeśli chcesz sprawdzić konkretny typ, możesz wykonać następujące czynności:
if let stringArray = obj as? [String] {
// obj is a string array. Do something with stringArray
}
else {
// obj is not a string array
}
Możesz użyć „jak!” i spowoduje to błąd w czasie wykonywania, jeśli obj
nie jest typu[String]
let stringArray = obj as! [String]
Możesz również sprawdzić jeden element na raz:
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
}
}
?
nie jest obecny. To brzmi jak as
i ?
po połączeniu wykona kontrolę czasu wykonywania. Kiedy byłoby właściwe używać as
bez ?
? Z góry dziękuję.
as
bez ?
jeśli nie ma sposobu, Twój program może odzyskać przedmiot nie jest tego rodzaju, ponieważ program będzie natychmiast zatrzymać, jeśli tak nie jest. Użycie instrukcji ?
in if
pozwala kontynuować program.
?
w tym przypadku spowoduje sprawdzenie typu „ogólnego”, jeśli tak, do klauzuli if, jeśli nie, do klauzuli else. Bez tego ?
nigdy nie zostałby wprowadzony i, jak wskazałeś, powoduje błąd w czasie wykonywania. Dzięki jeszcze raz.
?
Umożliwia przypisanie do powrotu nil
powodując if do zwrotu false
, a więc spada aż do innego rachunku. Myślę jednak, że wyjaśnienie to pomaga w zrozumieniu, ale if let
tak naprawdę jest szczególnym przypadkiem w kompilatorze
W Swift 2.2 - 5 możesz teraz:
if object is String
{
}
Następnie, aby przefiltrować tablicę:
let filteredArray = originalArray.filter({ $0 is Array })
Jeśli masz wiele typów do sprawdzenia:
switch object
{
case is String:
...
case is OtherClass:
...
default:
...
}
object
jako String
nawiasów klamrowych (przynajmniej w Swift 2), podczas gdy w let
rozwiązaniu można to zrobić.
object
w bloku jest w porządku.
object.uppercaseString
ponieważ typ zmiennej nie jest rzutowany na ten typ, po prostu sprawdziłeś, że obiekt (wskazany przez zmienną) toString
Jeśli chcesz tylko wiedzieć, czy obiekt jest podtypem danego typu, istnieje prostsze podejście:
class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}
func area (shape: Shape) -> Double {
if shape is Circle { ... }
else if shape is Rectangle { ... }
}
„Użyj operatora sprawdzania typu (is), aby sprawdzić, czy instancja jest określonego typu podklasy. Operator sprawdzania typu zwraca true, jeśli instancja jest tego typu podklasy, a false, jeśli nie jest. Fragment: Apple Inc. „Swift Programming Language”. iBooks .
W powyższym znaczeniu ważne jest wyrażenie „określonego typu podklasy”. Kompilator akceptuje użycie is Circle
i, is Rectangle
ponieważ ta wartość shape
jest zadeklarowana jako Shape
(nadklasa Circle
i Rectangle
).
Jeśli używasz typów pierwotnych, nadklasą byłoby Any
. Oto przykład:
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
nadal by tu działał? Dzięki.
object
jako Any
. Zaktualizowano z przykładem.
AnyObject
jest sugerowana, wydaje się, że została odparta z powodu AnyObject
braku dziedziczenia NSObject
. Jeśli Any
jest inaczej, byłoby to również świetne rozwiązanie. Dzięki.
Mam na to 2 sposoby:
if let thisShape = aShape as? Square
Lub:
aShape.isKindOfClass(Square)
Oto szczegółowy przykład:
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")
}
Edytuj: 3 teraz:
let myShape = Shape()
if myShape is Shape {
print("yes it is")
}
isKindOfClass
jest metodą NSObject
protokołu; powinno działać tylko dla klas, które przyjmują ją (wszystkie klasy zstępującego z NSObject oraz wszelkie niestandardowe klasy Swift że Przyjmuje jawnie)
dla swift4:
if obj is MyClass{
// then object type is MyClass Type
}
Załóżmy, że drawTriangle jest instancją UIView. Aby sprawdzić, czy drawTriangle jest typu UITableView:
W Swift 3 ,
if drawTriangle is UITableView{
// in deed drawTriangle is UIView
// do something here...
} else{
// do something here...
}
Można to również wykorzystać do klas zdefiniowanych przez ciebie. Możesz użyć tego do sprawdzenia widoków podrzędnych widoku.
Dlaczego nie skorzystać z wbudowanej funkcjonalności stworzonej specjalnie do tego zadania?
let myArray: [Any] = ["easy", "as", "that"]
let type = type(of: myArray)
Result: "Array<Any>"
Ostrzegam o tym:
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)
Wszystkie cztery ostatnie wiersze zwracają wartość true, ponieważ po wpisaniu
var r1:CGRect = CGRect()
print(r1 is String)
... drukuje „fałsz” oczywiście, ale Ostrzeżenie mówi, że rzutowanie z CGRect na ciąg nie powiedzie się. Więc niektóre typy są zmostkowane, a słowo kluczowe „is” wywołuje niejawną rzutowanie.
Lepiej użyj jednego z tych:
myObject.isKind(of: MyClass.self))
myObject.isMember(of: MyClass.self))
Jeśli chcesz tylko sprawdzić klasę bez ostrzeżenia z powodu nieużywanej zdefiniowanej wartości (niech someVariable ...), możesz po prostu zastąpić let przez boolean:
if (yourObject as? ClassToCompareWith) != nil {
// do what you have to do
}
else {
// do something else
}
Xcode zaproponował to, gdy użyłem let let i nie użyłem zdefiniowanej wartości.
Dlaczego nie skorzystać z czegoś takiego?
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
}
w Swift 3.
Swift 4.2, w moim przypadku przy użyciu funkcji isKind.
isKind (of :) Zwraca wartość logiczną, która wskazuje, czy odbiornik jest instancją danej klasy, czy instancją dowolnej klasy, która dziedziczy z tej klasy.
let items : [AnyObject] = ["A", "B" , ... ]
for obj in items {
if(obj.isKind(of: NSString.self)){
print("String")
}
}
Czytaj więcej https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418511-iskind
Dla kompletności opartej na przyjętej odpowiedzi i kilku innych:
let items : [Any] = ["Hello", "World", 1]
for obj in items where obj is String {
// obj is a String. Do something with str
}
Ale możesz także ( compactMap
również „mapować” wartości, które filter
nie):
items.compactMap { $0 as? String }.forEach{ /* do something with $0 */ ) }
I wersja wykorzystująca 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
}
}
Ale pozostając przy pytaniu, aby sprawdzić, czy jest to tablica (tj. [String]
):
let items : [Any] = ["Hello", "World", 1, ["Hello", "World", "of", "Arrays"]]
for obj in items {
if let stringArray = obj as? [String] {
print("\(stringArray)")
}
}
Lub bardziej ogólnie (patrz ta inna odpowiedź na pytanie ):
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?
nie zawsze da oczekiwany wynik, ponieważ as
nie sprawdza, czy typ danych jest określonego rodzaju, ale tylko wtedy, gdy typ danych można przekonwertować na lub reprezentować jako określony rodzaj.
Rozważ ten kod na przykład:
func handleError ( error: Error ) {
if let nsError = error as? NSError {
Każdy typ danych zgodny z Error
protokołem można przekonwertować na NSError
obiekt, więc zawsze się to powiedzie . Nie oznacza to jednak, że error
jest to w rzeczywistości NSError
przedmiot lub jego podklasa.
Prawidłowa kontrola typu to:
func handleError ( error: Error ) {
if type(of: error) == NSError.self {
Sprawdza to jednak tylko dokładny typ. Jeśli chcesz również dołączyć podklasę NSError
, powinieneś użyć:
func handleError ( error: Error ) {
if error is NSError.Type {
Jeśli masz taką odpowiedź:
{
"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
}
i chcesz sprawdzić wartość, is_stucked
która zostanie odczytana jako AnyObject, wszystko co musisz zrobić, to to
if let isStucked = response["is_stucked"] as? Bool{
if isStucked{
print("is Stucked")
}
else{
print("Not Stucked")
}
}
Jeśli nie wiesz, że w odpowiedzi z serwera otrzymasz tablicę słowników lub pojedynczy słownik, musisz sprawdzić, czy wynik zawiera tablicę, czy nie.
W moim przypadku zawsze otrzymuję szereg słowników, z wyjątkiem jednego. Aby to obsłużyć, użyłem poniższego kodu do szybkiego 3.
if let str = strDict["item"] as? Array<Any>
Tutaj jak? Tablica sprawdza, czy uzyskana wartość jest tablicą (elementów słownika). W innym przypadku możesz sobie poradzić, jeśli jest to pojedynczy element słownika, który nie jest przechowywany w tablicy.
Wersja Swift 5.2 i Xcode: 11.3.1 (11C504)
Oto moje rozwiązanie sprawdzania typu danych:
if let typeCheck = myResult as? [String : Any] {
print("It's Dictionary.")
} else {
print("It's not Dictionary.")
}
Mam nadzieję, że ci to pomoże.