web-dev-qa-db-fra.com

Comment trouvez-vous le type d'un objet (dans Swift)?

Lorsque vous essayez de comprendre un programme, ou dans certains cas, il est utile de pouvoir déterminer le type d'un élément. Je sais que le débogueur peut vous montrer des informations de type, et vous pouvez généralement vous fier à l'inférence de type pour ne pas spécifier le type dans ces situations, mais j'aimerais quand même avoir quelque chose comme Python type()

dynamicType (voir cette question )

Mise à jour: cela a été modifié dans une version récente de Swift, obj.dynamicType vous donne désormais une référence au type et non à l'instance du type dynamique.

Celui-ci semble le plus prometteur, mais jusqu'à présent, je n'ai pas été en mesure de connaître le type réel

class MyClass {
    var count = 0
}

let mc = MyClass()

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

J'ai aussi essayé d'utiliser une référence de classe pour instancier un nouvel objet, ce qui fonctionne , mais m'a donné une erreur en disant que je devais ajouter un initialiseur required:

travaux:

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

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

Encore qu’un petit pas vers la découverte du type d’un objet donné, bien que

edit : J'ai supprimé un nombre important de détails devenus inutiles - consultez l'historique des modifications si cela vous intéresse :)

238
Jiaaro

version de Swift 3:

type(of: yourObject)
250
Jérémy Lapointe

Swift 2.0:

La bonne façon de faire ce type d’introspection de type serait avec le Mirror struct ,

    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)

Ensuite, pour accéder au type lui-même à partir de la structure Mirror, vous utiliseriez la propriété subjectType comme suit:

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

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

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

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

Vous pouvez alors utiliser quelque chose comme ceci:

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

Le code dynamicType.printClassName provient d'un exemple du livre Swift. Je ne connais aucun moyen de saisir directement un nom de classe personnalisé, mais vous pouvez vérifier un type d'instance à l'aide du mot clé is, comme indiqué ci-dessous. Cet exemple montre également comment implémenter une fonction className personnalisée si vous souhaitez réellement que le nom de la classe soit une chaîne.

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

Note:
que les sous-classes de NSObject implémentent déjà leur propre fonction className. Si vous travaillez avec Cocoa, vous pouvez simplement utiliser cette propriété.

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

Depuis Xcode 6.0.1 (du moins, je ne sais pas quand ils l'ont ajouté), votre exemple d'origine fonctionne désormais:

class MyClass {
    var count = 0
}

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

Mise à jour:

Pour répondre à la question d'origine, vous pouvez réellement utiliser le moteur d'exécution Objective-C avec des objets simples Swift.

Essayez ce qui suit:

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))
41
Alex Pretzlav

Si vous devez simplement vérifier si la variable est de type X ou si elle est conforme à un protocole, vous pouvez utiliser is ou as? comme suit:

var unknownTypeVariable = …

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

Ceci est équivalent à isKindOfClass dans Obj-C.

Et cela équivaut à conformsToProtocol ou isMemberOfClass

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>
}
35
Valerii Lider

Swift 3:

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

Voici 2 façons que je recommande de le faire:

if let thisShape = aShape as? Square 

Ou:

aShape.isKindOfClass(Square)

Voici un exemple détaillé:

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

Pour Swift 3.

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

Pour Swift 2.0 - 2.

String(<Class-Name>)
7
techloverr

Dépend du cas d'utilisation. Mais supposons que vous vouliez faire quelque chose d’utile avec vos types "variables". La déclaration Swift switch est très puissante et peut vous aider à obtenir les résultats que vous recherchez ...

    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
    }

Dans ce cas, utilisez un dictionnaire simple contenant des paires clé/valeur pouvant être UInt, Int ou String. Dans la méthode .filter() du dictionnaire, je dois m'assurer que je teste correctement les valeurs et que je teste uniquement une chaîne lorsqu'il s'agit d'une chaîne, etc. L'instruction switch rend cela simple et sûr! En affectant 9 à la variable de type Any, le commutateur pour Int s’exécute. Essayez de le changer pour:

   let eValue:Any = "home9"

..et essayez à nouveau. Cette fois, il exécute le cas as String.

1
CPD
//: 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
0
Avi Cohen

Si vous recevez un avertissement "toujours vrai/échec", vous devrez peut-être transtyper vers Tout avant d'utiliser is

(foo as Any) is SomeClass
0
josef