Swift'te bir nesnenin belirli bir tür olup olmadığını kontrol etme


267

Oluşan bir dizi var AnyObject. Üzerinde yineleme ve dizi örnekleri olan tüm öğeleri bulmak istiyorum.

Swift'te bir nesnenin belirli bir türde olup olmadığını nasıl kontrol edebilirim?


Sorunuz, belirli bir nesnenin türünü bulma hakkında soru soruyor, ancak yalnızca bir nesnenin belirli bir türde olup olmadığını kontrol edebilen bir yanıtı kabul ettiniz. Sorunuzu özellikle buna göre düzenlemenizi öneririz, aksi takdirde birçok okuyucu kabul ettiğiniz yanıttan memnun olmayacaktır. (Diğer tüm cevaplar benzerdir, bu yüzden neyse ki sorunuzu daraltarak onları geçersiz kılmak konusunda endişelenmenize gerek yoktur.)
Jeremy Banks

Bu soruyu , yeniden açmak için oy verdiğim stackoverflow.com/q/24093433 adresinden ayırmak için düzenledim . Her ikisi de yararlı, benzer sorulardır, ancak cevaplar oldukça farklıdır, bu yüzden onları birbirinden ayırmak yararlı olacaktır.
Jeremy Banks

Yanıtlar:


304

Belirli bir türe karşı kontrol etmek istiyorsanız aşağıdakileri yapabilirsiniz:

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

"Gibi!" ve bu objtür değilse bir çalışma zamanı hatası atar[String]

let stringArray = obj as! [String]

Ayrıca bir kerede bir öğeyi kontrol edebilirsiniz:

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

Neden bu yalnızca çalışma zamanı hatası verir ve mevcut olmadığında derleme zamanı hatası ?vermez. Kulağa benziyor asve ?birleştirildiğinde çalışma zamanı kontrolü yapacak. Ne zaman asolmadan kullanmak uygun olur ?? Şimdiden teşekkürler.
Unheilig

@Unheilig Yalnızca , programınızın bu türden olmayan nesneden kurtulabilmesinin hiçbir yolu yoksa kullanmalısınız as, ?çünkü program yoksa hemen durur. Kullanılması ?halinde ifaçıklamaya programı devam etmesini sağlar.
drewag

Cevap için teşekkürler. Eğer yanılıyorsam düzelt: ?Bu durumda kullanmanın evet durumunda if deyimine, eğer değilse, diğer maddeye "genel" tipte bir kontrol gerçekleştireceğini düşündüm . ?Başka olmadan asla girilmez ve işaret ettiğiniz gibi bir çalışma zamanı hatasına neden olur. Tekrar teşekkürler.
Unheilig

@Unheilig Üzgünüm, ne söylediğini / sorduğunu anlamıyorum. ?Atama dönmek için izin verir nildönüşüne eğer deyimi neden falsebaşka açıklamaya üzerinden düşen ve bu nedenle. Ancak, açıklamanın anlayışa yardımcı olduğunu düşünüyorum, ancak if letaslında derleyicide özel bir durum
drewag

1
@Unheilig Doğru, bu yerel kapsamdayken değeri değiştirmek isterseniz var seçeneğini kullanabilirsiniz (bu değişiklikler kapsam dışında etkilemez)
14:14

202

In Swift 2,2-5 şimdi yapabilirsiniz:

if object is String
{
}

Ardından dizinizi filtrelemek için:

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

Kontrol etmek için birden fazla türünüz varsa:

    switch object
    {
    case is String:
        ...

    case is OtherClass:
        ...

    default:
        ...
    }

Bu çözüm kısadır, ancak bir dezavantajı vardır: Eğer kullanamazsınız objectbir şekilde Stringsahip iken, (Swift 2 en az) parantez içindeki letsolüsyon bunu yapabilirsiniz.
Ferran Maylinch

@FerranMaylinch Ne demek istediğini anlamıyorum çünkü objectblokta kullanmak iyidir.
anlamı önemli

@ anlam-meseleleri, örneğin object.uppercaseString, değişkenin türü bu türe String
dökülmediği için yapamayacaksınız

Kontrol ettiğiniz sınıf türünüz keyfi ise bunu nasıl yapabilirsiniz? Yalnızca bir değişkeniniz varsa, sınıf türü almanız gerekir mi?
Alex Zavatone

152

Yalnızca bir nesne olmadığını bilmek istiyorsanız olduğu belirli bir türden bir alt tipi sonra daha basit bir yaklaşım vardır:

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

func area (shape: Shape) -> Double {
  if shape is Circle { ... }
  else if shape is Rectangle { ... }
}

“Bir örneğin belirli bir alt sınıf türünde olup olmadığını kontrol etmek için tür kontrol operatörünü (is) kullanın. Tür denetim operatörü, örnek bu alt sınıf türündeyse true değerini, değilse false değerini döndürür. ” Alıntı: Apple Inc. “Hızlı Programlama Dili”. iBooks .

Yukarıda 'belirli bir alt sınıf türünden' ifadesi önemlidir. Kullanımı is Circleve is Rectanglebu değer, çünkü derleyici tarafından kabul edilir shapeolarak bildirilmiş Shape(a superclass Circleve Rectangle).

İlkel türler kullanıyorsanız, üst sınıf olacaktır Any. İşte bir örnek:

 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"

2
İlkel türü bir dizide saklarsam veya dizi ilkel türden biriyse, isyine de burada çalışır? Teşekkürler.
Unheilig

objectOlarak ilan ederseniz çalışmalıdır Any. Bir örnekle güncellendi.
GoZoner

Cevap için teşekkürler. Umut verici görünüyor. Benim tek kuşkum, AnyObjectönerilen aşağıdaki cevaba göre, AnyObjectmiras alınmadığı için çarpıtılmış gibi görünüyor NSObject. Farklıysa Any, bu aslında harika bir çözüm olacaktır. Teşekkürler.
Unheilig

21

Bunu yapmanın 2 yolu var:

if let thisShape = aShape as? Square 

Veya:

aShape.isKindOfClass(Square)

İşte ayrıntılı bir örnek:

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

Düzenleme: 3 şimdi:

let myShape = Shape()
if myShape is Shape {
    print("yes it is")
}

1
isKindOfClassNSObjectprotokolün bir yöntemidir ; sadece onu benimseyen sınıflar için çalışmalıdır (NSObject'ten inen tüm sınıflar ve bunu açıkça benimseyen herhangi bir özel Swift sınıfı)
Nicolas Miari


9

Varsayalım drawTriangle drawTriangle tipi UITableView olup olmadığını UIView.To çek bir örneğidir:

Gelen Swift 3 ,

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

Bu, kendiniz tanımladığınız sınıflar için de kullanılabilir. Bir görünümün alt görünümlerini kontrol etmek için bunu kullanabilirsiniz.


5

Neden bu görev için özel olarak oluşturulmuş yerleşik işlevselliği kullanmıyorsunuz?

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

Result: "Array<Any>"

type () işlevi basit
:)

5

Bu konuda uyarınız:

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) 

Son dört satırın tümü true değerini döndürür, çünkü

var r1:CGRect = CGRect()
print(r1 is String)

... elbette "yanlış" yazıyor, ancak bir Uyarı CGRect'ten String'e Yayınlama işleminin başarısız olduğunu söylüyor. Bu nedenle, bazı türler köprülenir ve 'is' anahtar sözcüğü örtük bir kadro çağırır.

Bunlardan birini daha iyi kullanmalısınız:

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

2

Sınıfı yalnızca kullanılmayan tanımlı değer nedeniyle bir uyarı almadan kontrol etmek istiyorsanız (let someVariable ...), let öğelerini bir boole ile değiştirebilirsiniz:

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

Xcode, let yolunu kullandığımda ve tanımlanan değeri kullanmadığımda bunu önerdi.


2

Neden böyle bir şey kullanmıyorsun?

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'te.


2

Swift 4.2, Benim durumumda isKind işlevini kullanma.

isKind (of :) Alıcının belirli bir sınıf örneği mi yoksa o sınıftan miras alan herhangi bir sınıf örneği mi olduğunu gösteren bir Boolean değeri döndürür.

  let items : [AnyObject] = ["A", "B" , ... ]
  for obj in items {
    if(obj.isKind(of: NSString.self)){
      print("String")
    }
  }

Readmore https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418511-iskind


1
Bu Swift değil. Kakao ve sadece Amaç C için çalışacağı yerde çalışıyor
matt

1

myObject as? Stringa nildeğilse döndürür . Aksi takdirde, a döndürür , böylece dizenin kendisine erişebilir veya güvenle atabilirsiniz .myObjectStringString?myObject!myObject! as String


1

Hızlı 3:

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

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

1

Sadece kabul edilen cevaba ve diğerlerine dayanan tamlık uğruna:

let items : [Any] = ["Hello", "World", 1]

for obj in items where obj is String {
   // obj is a String. Do something with str
}

Ancak şunları da yapabilirsiniz ( olmayan compactMapdeğerleri "eşleştirir" filter):

items.compactMap { $0 as? String }.forEach{ /* do something with $0 */ ) }

Ve aşağıdakileri kullanan bir sürüm 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
    }
}

Ancak soruya sadık kalmak, bunun bir dizi olup olmadığını kontrol etmek (yani [String]):

let items : [Any] = ["Hello", "World", 1, ["Hello", "World", "of", "Arrays"]]

for obj in items {
  if let stringArray = obj as? [String] {
    print("\(stringArray)")
  }
}

Veya daha genel olarak ( bu diğer soru cevabına bakınız ):

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

1

as?her zaman beklenen sonucu asvermez, çünkü bir veri türünün belirli bir tür olup olmadığını test etmez , ancak yalnızca bir veri türünün belirli bir türe dönüştürülebilir veya temsil edilebildiğini test eder .

Örneğin bu kodu düşünün:

func handleError ( error: Error ) {
    if let nsError = error as? NSError {

ErrorProtokole uyan her veri türü bir NSErrornesneye dönüştürülebilir , böylece bu her zaman başarılı olacaktır . Ancak bu erroraslında bir NSErrornesne ya da onun bir alt sınıfı olduğu anlamına gelmez .

Doğru tip kontrolü şu şekildedir:

func handleError ( error: Error ) {
    if type(of: error) == NSError.self {

Ancak, bu yalnızca tam türü kontrol eder. Ayrıca alt sınıfını da eklemek NSErroristiyorsanız şunu kullanmalısınız:

func handleError ( error: Error ) {
    if error is NSError.Type {

0

Böyle bir Yanıtınız varsa:

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

ve is_stuckedAnyObject olarak okunacak değeri kontrol etmek istiyorsanız , tek yapmanız gereken bu

if let isStucked = response["is_stucked"] as? Bool{
  if isStucked{
      print("is Stucked")
  }
  else{
      print("Not Stucked")
 }
}

0

Sunucudan gelen yanıtta bir dizi sözlük veya tek bir sözlük alacağınızı bilmiyorsanız, sonucun bir dizi içerip içermediğini kontrol etmeniz gerekir.
Benim durumumda her zaman bir kez dışında bir dizi sözlük almak. Yani, ele almak için ben hızlı 3 için aşağıdaki kodu kullandım.

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

Burada olduğu gibi? Dizi, elde edilen değerin dizi (sözlük öğelerinin) olup olmadığını kontrol eder. Aksi takdirde, bir dizinin içinde tutulmayan tek bir sözlük öğesi olup olmadığını işleyebilirsiniz.


0

Swift 5.2 ve Xcode Sürümü: 11.3.1 (11C504)

İşte veri türü kontrol benim çözüm:

 if let typeCheck = myResult as? [String : Any] {
        print("It's Dictionary.")
    } else { 
        print("It's not Dictionary.") 
    }

Umarım bu sana yardımcı olur.


Eski bir soruyu cevaplarken, özellikle de zaten kabul edilmiş bir cevabı olan bir soru için cevabınızın nasıl yardımcı olduğunu açıklamak için bir bağlam eklediyseniz, cevabınız diğer StackOverflow kullanıcıları için çok daha yararlı olacaktır. Bakınız: İyi bir cevabı nasıl yazarım .
David Buck
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.