Ответ 1
Версия Swift 3:
type(of: yourObject)
При попытке понять программу или в некоторых угловых случаях полезно иметь возможность действительно узнать, что это за тип. Я знаю, что отладчик может показать вам некоторую информацию о типе, и вы обычно можете полагаться на вывод типа, чтобы уйти, не указав тип в этих ситуациях, но все же мне бы хотелось иметь что-то вроде Python type()
Обновление: это было изменено в недавней версии 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()
Еще только небольшой шаг к фактическому обнаружению типа любого данного объекта, хотя
edit. Я удалил значительное количество ненужных деталей - посмотрите, пожалуйста, историю изменений, если вам интересно:
Версия Swift 3:
type(of: yourObject)
Swift 2.0:
Правильный способ сделать такой тип самоанализа был бы с помощью структуры Mirror,
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
вы должны использовать свойство 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. Если вы работаете с Cocoa, вы можете просто использовать это свойство.
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'
Чтобы ответить на первоначальный вопрос, вы можете успешно использовать среду выполнения Objective 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>
}
Свифт 3:
if unknownType is MyClass {
//unknownType is of class type MyClass
}
Вот два способа, я рекомендую сделать это:
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")
}
Для Swift 3.0
String(describing: <Class-Name>.self)
Для Swift 2.0 - 2.3
String(<Class-Name>)
Зависит от варианта использования. Но позвольте предположить, что вы хотите сделать что-то полезное с вашими "переменными" типами. Оператор Swift 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 = $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
}
В этом случае используйте простой словарь, содержащий пары ключ/значение, которые могут быть UInt, Int или String. В методе .filter()
словаря мне нужно убедиться, что я правильно проверяю значения и проверяю только строку String, когда она является строкой и т.д. Оператор switch делает это простым и безопасным!
Назначая 9 переменной типа Any, она делает ключ для выполнения Int. Попробуйте изменить его на:
let eValue:Any = "home9"
.. и повторите попытку. На этот раз он выполнит случай as String
.
Если вы получаете предупреждение "всегда правдиво/не удается", вам может потребоваться передать Any, прежде чем использовать 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