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()
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 :)
version de Swift 3:
type(of: yourObject)
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!")
}
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()
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`
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))
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>
}
Swift 3:
if unknownType is MyClass {
//unknownType is of class type MyClass
}
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")
}
Pour Swift 3.
String(describing: <Class-Name>.self)
Pour Swift 2.0 - 2.
String(<Class-Name>)
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
.
//: 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
Si vous recevez un avertissement "toujours vrai/échec", vous devrez peut-être transtyper vers Tout avant d'utiliser is
(foo as Any) is SomeClass