Bir nesnenin türünü nasıl öğrenirsiniz (Swift'te)?


255

Bir programı anlamaya çalışırken veya bazı köşe durumlarda, bir şeyin ne olduğunu gerçekten bulmak yararlıdır. Hata ayıklayıcının size bazı tür bilgiler gösterebileceğini biliyorum ve genellikle bu tür durumlarda türü belirtmekten kaçınmak için tür çıkarımına güvenebilirsiniz, ancak yine de gerçekten Python gibi bir şeye sahip olmak istiyorumtype()

dynamicType ( bu soruya bakın )

Güncelleme: Bu, Swift'in son bir sürümünde değiştirildi, obj.dynamicTypeşimdi size dinamik türün örneğine değil, türe referans veriyor.

Bu en umut verici görünüyor, ancak şimdiye kadar gerçek türü bulamadım

class MyClass {
    var count = 0
}

let mc = MyClass()

# update: this now evaluates as true
mc.dynamicType === MyClass.self

Ayrıca , işe yarayan yeni bir nesne başlatmak için bir sınıf başvurusu kullanarak denedim , ama garip bir şekilde bir requiredbaşlatıcı eklemeniz gerektiğini söyleyerek bir hata verdi :

İşler:

class MyClass {
    var count = 0
    required init() {
    }
}

let myClass2 = MyClass.self
let mc2 = MyClass2()

Yine de, verilen herhangi bir nesnenin türünü gerçekten keşfetmeye yönelik küçük bir adım

edit : Şimdi önemli olmayan birçok önemli ayrıntıyı kaldırdım - ilgileniyorsanız düzenleme geçmişine bakın :)



1
İlginçtir, print(mc)ya dump(mc)da orada bir yerde sınıf adını içeren bir özet ( toString(mc)veya alabilirsiniz reflect(mc).summary) basacaktır . Ancak sadece sınıf adını kendiniz nasıl alacağınız açık değildir.
newacct

@David benzer, ancak tüm değişkenler sınıf örneğidir. Ayrıca bu sorular, türün programcının aradıklarıyla eşleşip eşleşmediğini kontrol etmekle ilgiliydi, oysa sadece toptan satış türünü bulmayı umuyorum
Jiaaro


Yanıtlar:


286

Swift 3 sürümü:

type(of: yourObject)

8
Eğlenceli gerçek. Bu, örtük olarak açılmamış seçeneklerle çalışmaz! yani var myVar: SomeType!. Derleyici (aka 'ImplicitlyUnwrappedOptional <sometype> .Type') beklenen argüman türü 'AnyClass' (aka 'AnyObject.Type') Derleyici ekleyerek öneririz türündeki 'sometype! .Type' değerini dönüştürülemez hata" verir as! AnyClasssonra tip ama sonra program bazı "EXC_BAD_INSTRUCTION" ve deşifre edemediğim diğer jiberrish ile çöküyor
LightningStryk

1
Gerçekten, bu Swift 3'ün var olduğu kabul edilen cevap olmalı. Teşekkürler Jeremy!
biomiker

1
Belirli bir tür adı arıyorsanız, tür bir protokol türündeyse, bu sizin için çalışmayabilir.
Chris Prince

2
Eğer Stringtür olarak geçirilen bir varsa, Anyo type(of:)zaman çıktı Any, değil String.
ScottyBlades

1
@ScottyBlades yani çözüm ne olacak. Sağlayabilir misiniz?
Mubin Mall

109

Swift 2.0:

Bu tür bir tür içgözlemini yapmanın doğru yolu Ayna yapısıyla ,

    let stringObject:String = "testing"
    let stringArrayObject:[String] = ["one", "two"]
    let viewObject = UIView()
    let anyObject:Any = "testing"

    let stringMirror = Mirror(reflecting: stringObject)
    let stringArrayMirror = Mirror(reflecting: stringArrayObject)
    let viewMirror = Mirror(reflecting: viewObject)
    let anyMirror = Mirror(reflecting: anyObject)

Daha sonra türün kendisine Mirroryapıdan erişmek için özelliği şöyle kullanırsınız subjectType:

    // Prints "String"
    print(stringMirror.subjectType)

    // Prints "Array<String>"
    print(stringArrayMirror.subjectType)

    // Prints "UIView"
    print(viewMirror.subjectType)

    // Prints "String"
    print(anyMirror.subjectType)

Daha sonra böyle bir şey kullanabilirsiniz:

    if anyMirror.subjectType == String.self {
        print("anyObject is a string!")
    } else {
        print("anyObject is not a string!")
    }

7
Bu harika. Yansıtılan nesne isteğe bağlı türdeyse, isteğe bağlı olmayan bir türle karşılaştırmanın başarısız olacağını unutmayın. Stringve Optional(String)aynı değil.
Thomas Verbeek

1
Tam olarak aradığım şey, nesnenin türünün ne olduğunu bilmek istedi
Joseph

Bu bağlamda, isteğe bağlı olmayan türlerle karşılaştırılırken başarısız olmayacak bir karşılaştırma türü var mı?
Chris Prince

Aradığım şey buydu. Teşekkürler @Gudbergur.
Mubin Mall

60

dynamicType.printClassNameKod Swift kitapta örnek değil. Doğrudan özel bir sınıf adı almanın bir yolu yok, ancak isaşağıda gösterildiği gibi anahtar kelimeyi kullanarak bir örnek türünü kontrol edebilirsiniz . Bu örnek, sınıf adını gerçekten bir dize olarak istiyorsanız, özel bir className işlevinin nasıl uygulanacağını da gösterir.

class Shape {
    class func className() -> String {
        return "Shape"
    }
}

class Square: Shape {
    override class func className() -> String {
        return "Square"
    }
}

class Circle: Shape {
    override class func className() -> String {
        return "Circle"
    }
}

func getShape() -> Shape {
    return Square() // hardcoded for example
}

let newShape: Shape = getShape()
newShape is Square // true
newShape is Circle // false
newShape.dynamicType.className() // "Square"
newShape.dynamicType.className() == Square.className() // true

Not: zaten kendi className işlevinin
alt sınıfları NSObjectuygulamak. Kakao ile çalışıyorsanız, sadece bu özelliği kullanabilirsiniz.

class MyObj: NSObject {
    init() {
        super.init()
        println("My class is \(self.className)")
    }
}
MyObj()

2
Hey, ne zaman değiştiğinden emin değilim, ama Alex Pretzlav'nın işaret ettiği gibi, davranış değişti.
Jiaaro

1
Evet. Swift 3.0'dan itibaren subjectTypeartık mevcut değildir ve dynamicTypederleyiciden kullanımdan kaldırılmasına neden olur.
Raphael

41

İtibariyle Xcode 6.0.1 (onlar eklendiğinde en azından emin), orijinal örnek şimdi çalışır:

class MyClass {
    var count = 0
}

let mc = MyClass()
mc.dynamicType === MyClass.self // returns `true`

Güncelleme:

Orijinal soruyu cevaplamak için, Objective-C çalışma zamanını düz Swift nesnelerle başarıyla kullanabilirsiniz.

Takip etmeyi dene:

import Foundation
class MyClass { }
class SubClass: MyClass { }

let mc = MyClass()
let m2 = SubClass()

// Both of these return .Some("__lldb_expr_35.SubClass"), which is the fully mangled class name from the playground
String.fromCString(class_getName(m2.dynamicType))
String.fromCString(object_getClassName(m2))
// Returns .Some("__lldb_expr_42.MyClass")
String.fromCString(object_getClassName(mc))

Görünüşe göre bunu bir örnek yerine türü verecek şekilde değiştirdiler.
Jiaaro

@Jiaaro, cevabımı asıl sorunuzda aradığınızı düşündüğüm şeyle güncelledim
Alex Pretzlav

36

Değişkenin X türünde olup olmadığını veya bazı protokole uygun olup olmadığını kontrol etmeniz gerekiyorsa , aşağıdakileri isveya as?aşağıdaki gibi kullanabilirsiniz :

var unknownTypeVariable =if unknownTypeVariable is <ClassName> {
    //the variable is of type <ClassName>
} else {
    //variable is not of type <ClassName>
}

Bu, isKindOfClassObj-C'de eşdeğerdir .

Ve bu conformsToProtocol, veyaisMemberOfClass

var unknownTypeVariable =if let myClass = unknownTypeVariable as? <ClassName or ProtocolName> {
    //unknownTypeVarible is of type <ClassName or ProtocolName>
} else {
    //unknownTypeVariable is not of type <ClassName or ProtocolName>
}

Cevabınızın ikinci kısmı yanlış. as?Koşullu döküm ile 'if let' ifadesi de aynı şeyi yapar, aynı isKindOfClasszamanda Başarılı olması durumunda dökümün sonucunu da sağlar.
awolf

Eşdeğeri isMemberOfClasskoşuldur object.dynamicType == ClassName.self.
awolf

18

Hızlı 3:

if unknownType is MyClass {
   //unknownType is of class type MyClass
}

Sanırım Swift 3'ten önceis var mı?
Nicolas Miari

10

Swift 3.0 için

String(describing: <Class-Name>.self)

Swift 2.0 - 2.3 için

String(<Class-Name>)

1
Bu cevabın benim için doğru olmasıyla ilgili önemli olan, ortaya çıkan dizenin sınıf adıyla tam olarak eşleşmesidir - bu yüzden bunu NSManagedObject alt sınıfından bir Core Data varlık adı almak için kullanabilirim. Swift3 sürümünü kullandım.
Kendall Helmstetter Gelner

8

İşte bunu yapmanızı tavsiye ettiğim 2 yol:

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

2
print( aShape is Square ), isoperatör daha çok tercih edilir.
DawnSong

Nesnelerin türünü almak benim için iyi bir çözüm.
nihasmata

1

Kullanım durumuna bağlıdır. Ancak "değişken" türlerinizle faydalı bir şeyler yapmak istediğinizi varsayalım. Swift switchifadesi çok güçlü ve aradığınız sonuçları almanıza yardımcı olabilir ...

    let dd2 = ["x" : 9, "y" : "home9"]
    let dds = dd2.filter {
        let eIndex = "x"
        let eValue:Any = 9
        var r = false

        switch eValue {
        case let testString as String:
            r = $1 == testString
        case let testUInt as UInt:
            r = $1 == testUInt
        case let testInt as Int:
            r = $1 == testInt
        default:
            r = false
        }

        return r && $0 == eIndex
    }

Bu durumda, UInt, Int veya String olabilecek anahtar / değer çiftlerini içeren basit bir sözlüğe sahip olun. Gelen .filter()bir dize olduğunda sözlüğe yöntemle, ben switch deyimi bu basit ve güvenli hale getirir, vb bir dize için doğru değerler ve sadece test için emin Testi yapmak gerekir! Any türündeki değişkene 9 atayarak, Int yürütme anahtarını yapar. Bunu şu şekilde değiştirmeyi deneyin:

   let eValue:Any = "home9"

..ve tekrar deneyin. Bu sefer as Stringdavayı yürütür .


1

"Her zaman doğru / başarısız" uyarısı alırsanız, kullanmadan önce Herhangi birine yayınlamanız gerekebilir is

(foo as Any) is SomeClass

0
//: Playground - noun: a place where people can play

import UIKit

class A {
    class func a() {
        print("yeah")
    }

    func getInnerValue() {
        self.dynamicType.a()
    }
}

class B: A {
    override class func a() {
        print("yeah yeah")
    }
}

B.a() // yeah yeah
A.a() // yeah
B().getInnerValue() // yeah yeah
A().getInnerValue() // yeah
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.