Как узнать тип объекта (в Swift)?
при попытке понять программу, или в некоторых угловых случаях, полезно иметь возможность на самом деле выяснить, какой тип что-то есть. Я знаю, что отладчик может показать вам некоторую информацию о типе, и вы обычно можете полагаться на вывод типа, чтобы уйти от указания типа в этих ситуациях, но все же мне очень хотелось бы иметь что-то вроде Python type()
dynamicType (см. этот вопрос)
обновление: это было изменено в последней версии Swift,obj.dynamicType
Теперь дает вам ссылку на тип, а не экземпляр динамического типа.
этот кажется наиболее перспективным, но до сих пор я не смог выяснить реальный тип
class MyClass {
var count = 0
}
let mc = MyClass()
# update: this now evaluates as true
mc.dynamicType === MyClass.self
Я также попытался использовать ссылку на класс для создания экземпляра нового объекта, который тут работа, но странно дал мне ошибку говоря, что я должен добавить required
инициализатор:
работает:
class MyClass {
var count = 0
required init() {
}
}
let myClass2 = MyClass.self
let mc2 = MyClass2()
все еще только a небольшой шаг к фактическому обнаружению типа любого данного объекта, хотя
edit: Я удалил значительное количество теперь неуместных деталей-посмотрите на историю редактирования, если вам интересно :)
11 ответов:
в Swift 2.0 правильный способ сделать такой тип самоанализа будет с зеркало структуры,
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)
затем, чтобы получить доступ к самому типу из
Mirror
struct вы бы использовали свойствоsubjectType
вот так:// Prints "String" print(stringMirror.subjectType) // Prints "Array<String>" print(stringArrayMirror.subjectType) // Prints "UIView" print(viewMirror.subjectType) // Prints "String" print(anyMirror.subjectType)
затем вы можете использовать что-то вроде этого:
if anyMirror.subjectType == String.self { print("anyObject is a string!") } else { print("anyObject is not a string!") }
" dynamicType.код printClassName " взят из примера в книге Swift. Я не знаю, как напрямую захватить имя пользовательского класса, но вы можете проверить тип экземпляров, используя ключевое слово "is", как показано ниже. В этом примере также показано, как реализовать пользовательскую функцию className, если вы действительно хотите имя класса в виде строки.
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
обратите внимание, что подклассы NSObject уже реализуют свою собственную функцию className. Если вы работаете с какао, вы можете просто использовать это свойство.
class MyObj: NSObject { init() { super.init() println("My class is \(self.className)") } } MyObj()
начиная с Xcode 6.0.1 (по крайней мере, не уверен, когда они добавили его), ваш исходный пример теперь работает:
class MyClass { var count = 0 } let mc = MyClass() mc.dynamicType === MyClass.self // returns `true`
обновление:
чтобы ответить на исходный вопрос, вы можете успешно использовать среду выполнения Obj-C с простыми объектами Swift.
попробуйте следующее:
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))
Если вам просто нужно проверить, является ли переменная типа X, или что она соответствует некоторому протоколу, то вы можете использовать
is
илиas?
следующим образом:var unknownTypeVariable = … if unknownTypeVariable is <ClassName> { //the variable is of type <ClassName> } else { //variable is not of type <ClassName> }
эквивалентно
isKindOfClass
в Obj-C.и это эквивалентно
conformsToProtocol
или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> }
вот 2 способа, которые я рекомендую сделать это:
if let thisShape = aShape as? Square
или:
aShape.isKindOfClass(Square)
вот подробный пример:
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") }
зависит от варианта использования. Но давайте предположим, что вы хотите сделать что-то полезное с вашими "переменными" типами. Свифт
switch
утверждение очень мощный и может помочь вам получить результаты, которые вы ищете...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 = == testString case let testUInt as UInt: r = == testUInt case let testInt as Int: r = == testInt default: r = false } return r && == eIndex }
в этом случае есть простой словарь, который содержит пары ключ/значение, которые могут быть UInt, Int или String. В
.filter()
метод в словаре, мне нужно убедиться, что я правильно тестирую значения и только тестирую строку, когда это строка и т. д. Этот оператор switch делает это простым и безопасным! Назначая 9 переменной типа Any, он делает переключатель для int execute. Попробуйте изменить его на:let eValue:Any = "home9"
..и попробуй еще раз. На этот раз он выполняет
as String
случае.
Если вы получаете предупреждение "всегда true/fails", вам может потребоваться привести к любому перед использованием
is
(foo as Any) is SomeClass
//: 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