Как напечатать тип или класс переменной в Swift?

Есть ли способ распечатать тип среды выполнения в swift? Например:

var now = NSDate()
var soon = now.dateByAddingTimeInterval(5.0)

println("\(now.dynamicType)") 
// Prints "(Metatype)"

println("\(now.dynamicType.description()")
// Prints "__NSDate" since objective-c Class objects have a "description" selector

println("\(soon.dynamicType.description()")
// Compile-time error since ImplicitlyUnwrappedOptional<NSDate> has no "description" method

В приведенном выше примере я ищу способ показать, что переменная "скоро" имеет тип ImplicitlyUnwrappedOptional<NSDate> или, по крайней мере, NSDate!.

Ответ 1

Обновление сентябрь 2016 года

Swift 3.0: используйте type(of:), например. type(of: someThing) (поскольку ключевое слово dynamicType было удалено)

Обновить октябрь 2015:

Я обновил приведенные ниже примеры до нового синтаксиса Swift 2.0 (например, println был заменен на print, toString() теперь String()).

Из примечаний к выпуску Xcode 6.3:

@nschum указывает в комментариях, что примечания к выпуску Xcode 6.3 показывают другой способ:

Значения типов теперь печатаются как полное имя имени demangled при использовании с println или интерполяция строк.

import Foundation

class PureSwiftClass { }

var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"

print( "String(myvar0.dynamicType) -> \(myvar0.dynamicType)")
print( "String(myvar1.dynamicType) -> \(myvar1.dynamicType)")
print( "String(myvar2.dynamicType) -> \(myvar2.dynamicType)")
print( "String(myvar3.dynamicType) -> \(myvar3.dynamicType)")

print( "String(Int.self)           -> \(Int.self)")
print( "String((Int?).self         -> \((Int?).self)")
print( "String(NSString.self)      -> \(NSString.self)")
print( "String(Array<String>.self) -> \(Array<String>.self)")

Какие выходы:

String(myvar0.dynamicType) -> __NSCFConstantString
String(myvar1.dynamicType) -> PureSwiftClass
String(myvar2.dynamicType) -> Int
String(myvar3.dynamicType) -> String
String(Int.self)           -> Int
String((Int?).self         -> Optional<Int>
String(NSString.self)      -> NSString
String(Array<String>.self) -> Array<String>

Обновление для Xcode 6.3:

Вы можете использовать _stdlib_getDemangledTypeName():

print( "TypeName0 = \(_stdlib_getDemangledTypeName(myvar0))")
print( "TypeName1 = \(_stdlib_getDemangledTypeName(myvar1))")
print( "TypeName2 = \(_stdlib_getDemangledTypeName(myvar2))")
print( "TypeName3 = \(_stdlib_getDemangledTypeName(myvar3))")

и получить это как вывод:

TypeName0 = NSString
TypeName1 = __lldb_expr_26.PureSwiftClass
TypeName2 = Swift.Int
TypeName3 = Swift.String

Оригинальный ответ:

До Xcode 6.3 _stdlib_getTypeName получил измененное имя переменной. Запись в блоге Ewan Swick помогает расшифровать эти строки:

например. _TtSi обозначает внутренний тип Swift Int.

У Майка Эша отличная запись в блоге, посвященная той же теме.

Ответ 2

Изменить: Новая функция toString была введена в Swift 1.2 (Xcode 6.3).

Теперь вы можете напечатать demangled тип любого типа с помощью .self и любого экземпляра с помощью .dynamicType:

struct Box<T> {}

toString("foo".dynamicType)            // Swift.String
toString([1, 23, 456].dynamicType)     // Swift.Array<Swift.Int>
toString((7 as NSNumber).dynamicType)  // __NSCFNumber

toString((Bool?).self)                 // Swift.Optional<Swift.Bool>
toString(Box<SinkOf<Character>>.self)  // __lldb_expr_1.Box<Swift.SinkOf<Swift.Character>>
toString(NSStream.self)                // NSStream

Попробуйте вызвать YourClass.self и yourObject.dynamicType.

Ссылка: https://devforums.apple.com/thread/227425.

Ответ 3

Это то, что вы ищете?

println("\(object_getClassName(now))");

Он печатает "__NSDate"

ОБНОВЛЕНИЕ. Обратите внимание, что это больше не работает с Beta05

Ответ 4

Swift 3.0

let string = "Hello"
let stringArray = ["one", "two"]
let dictionary = ["key": 2]

print(type(of: string)) // "String"

// Get type name as a string
String(describing: type(of: string)) // "String"
String(describing: type(of: stringArray)) // "Array<String>"
String(describing: type(of: dictionary)) // "Dictionary<String, Int>"

// Get full type as a string
String(reflecting: type(of: string)) // "Swift.String"
String(reflecting: type(of: stringArray)) // "Swift.Array<Swift.String>"
String(reflecting: type(of: dictionary)) // "Swift.Dictionary<Swift.String, Swift.Int>"

Ответ 5

Мой текущий Xcode - версия 6.0 (6A280e).

import Foundation

class Person { var name: String; init(name: String) { self.name = name }}
class Patient: Person {}
class Doctor: Person {}

var variables:[Any] = [
    5,
    7.5,
    true,
    "maple",
    Person(name:"Sarah"),
    Patient(name:"Pat"),
    Doctor(name:"Sandy")
]

for variable in variables {
    let typeLongName = _stdlib_getDemangledTypeName(variable)
    let tokens = split(typeLongName, { $0 == "." })
    if let typeName = tokens.last {
        println("Variable \(variable) is of Type \(typeName).")
    }
}

Вывод:

Variable 5 is of Type Int.
Variable 7.5 is of Type Double.
Variable true is of Type Bool.
Variable maple is of Type String.
Variable Swift001.Person is of Type Person.
Variable Swift001.Patient is of Type Patient.
Variable Swift001.Doctor is of Type Doctor.

Ответ 6

Как и Xcode 6.3 с Swift 1.2, вы можете просто преобразовать значения типа в полный demangled String.

toString(Int)                   // "Swift.Int"
toString(Int.Type)              // "Swift.Int.Type"
toString((10).dynamicType)      // "Swift.Int"
println(Bool.self)              // "Swift.Bool"
println([UTF8].self)            // "Swift.Array<Swift.UTF8>"
println((Int, String).self)     // "(Swift.Int, Swift.String)"
println((String?()).dynamicType)// "Swift.Optional<Swift.String>"
println(NSDate)                 // "NSDate"
println(NSDate.Type)            // "NSDate.Type"
println(WKWebView)              // "WKWebView"
toString(MyClass)               // "[Module Name].MyClass"
toString(MyClass().dynamicType) // "[Module Name].MyClass"

Ответ 7

Вы все равно можете получить доступ к классу через className (который возвращает String).

На самом деле существует несколько способов получить класс, например classForArchiver, classForCoder, classForKeyedArchiver (all return AnyClass!).

Вы не можете получить тип примитива (примитив не класс).

Пример:

var ivar = [:]
ivar.className // __NSDictionaryI

var i = 1
i.className // error: 'Int' does not have a member named 'className'

Если вы хотите получить тип примитива, вы должны использовать bridgeToObjectiveC(). Пример:

var i = 1
i.bridgeToObjectiveC().className // __NSCFNumber

Ответ 8

Вы можете использовать отображение, чтобы получить информацию об объекте.
Например, имя класса объекта:

var classname = reflect(now).summary

Ответ 9

Мне повезло:

let className = NSStringFromClass(obj.dynamicType)

Ответ 10

Xcode 8 Swift 3.0 тип использования (из:)

let className = "\(type(of: instance))"

Ответ 11

В Xcode 8, Swift 3.0

Шаги:

1. Получить Тип:

Вариант 1:

let type : Type = MyClass.self  //Determines Type from Class

Вариант 2:

let type : Type = type(of:self) //Determines Type from self

2. Преобразовать тип в строку:

let string : String = "\(type)" //String

Ответ 12

В Swift 3.0 вы можете использовать type(of:), поскольку ключевое слово dynamicType было удалено.

Ответ 13

SWIFT 5

В последнем выпуске Swift 3 мы можем получить симпатичные описания имен типов через инициализатор String. Как, например, print(String(describing: type(of: object))). Где object может быть переменной экземпляра, такой как массив, словарь, Int, NSDate, экземпляр пользовательского класса и т.д.

Вот мой полный ответ: Получить имя класса объекта в виде строки в Swift

Этот вопрос ищет способ получить имя класса объекта в виде строки, но я также предложил другой способ получения имени класса переменной, которая не является подклассом NSObject. Вот:

class Utility{
    class func classNameAsString(obj: Any) -> String {
        //prints more readable results for dictionaries, arrays, Int, etc
        return String(describing: type(of: obj))
    }
}

Я сделал статическую функцию, которая принимает в качестве параметра объект типа Any и возвращает его имя класса как String :).

Я протестировал эту функцию с некоторыми переменными, такими как:

    let diccionary: [String: CGFloat] = [:]
    let array: [Int] = []
    let numInt = 9
    let numFloat: CGFloat = 3.0
    let numDouble: Double = 1.0
    let classOne = ClassOne()
    let classTwo: ClassTwo? = ClassTwo()
    let now = NSDate()
    let lbl = UILabel()

и вывод был:

  • словарь имеет тип словарь
  • массив имеет тип Array
  • numInt имеет тип Int
  • numFloat относится к типу CGFloat
  • numDouble типа Double
  • classOne имеет тип: ClassOne
  • classTwo имеет тип: ClassTwo
  • сейчас имеет тип: Дата
  • lbl имеет тип: UILabel

Ответ 14

В верхнем ответе нет рабочего примера нового способа сделать это с помощью type(of: Итак, чтобы помочь новичкам, таким как я, вот рабочий пример, взятый в основном из документации Apple здесь - https://developer.apple.com/документация/быстрое /2885064-типа

doubleNum = 30.1

func printInfo(_ value: Any) {
    let varType = type(of: value)
    print("'\(value)' of type '\(varType)'")
}

printInfo(doubleNum)
//'30.1' of type 'Double'

Ответ 15

При использовании Cocoa (не CocoaTouch) вы можете использовать свойство className для объектов, которые являются подклассами NSObject.

println(now.className)

Это свойство недоступно для обычных объектов Swift, которые не являются подклассами NSObject (и на самом деле в Swift нет корневого идентификатора или типа объекта).

class Person {
    var name: String?
}

var p = Person()
println(person.className) // <- Compiler error

В CocoaTouch в настоящее время нет способа получить строковое описание типа данной переменной. Аналогичная функциональность также не существует для примитивных типов в Cocoa или CocoaTouch.

Swift REPL может распечатывать сводку значений, включая их тип, поэтому возможно, что этот способ интроспекции будет возможен через API в будущем.

EDIT: dump(object), похоже, делает трюк.

Ответ 16

Я пробовал некоторые другие ответы здесь, но milage, похоже, очень относится к тому, что является объектом underling.

Однако я нашел способ, которым вы можете получить имя класса Object-C для объекта, выполнив следующее:

now?.superclass as AnyObject! //replace now with the object you are trying to get the class name for

Вот и пример того, как вы его используете:

let now = NSDate()
println("what is this = \(now?.superclass as AnyObject!)")

В этом случае он будет печатать NSDate в консоли.

Ответ 17

Я нашел это решение, которое, надеюсь, может работать для кого-то другого. Я создал метод класса для доступа к значению. Пожалуйста, имейте в виду, что это будет работать только для подкласса NSObject. Но, по крайней мере, это чистое и аккуратное решение.

class var className: String!{
    let classString : String = NSStringFromClass(self.classForCoder())
    return classString.componentsSeparatedByString(".").last;
}

Ответ 18

В последнем XCode 6.3 с Swift 1.2 это единственный способ, которым я нашел:

if view.classForCoder.description() == "UISegment" {
    ...
}

Ответ 19

В lldb с версии бета 5 вы можете увидеть класс объекта с помощью команды:

fr v -d r shipDate

который выводит что-то вроде:

(DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940

Развернутая команда означает что-то вроде:

Frame Variable (напечатать переменную фрейма) -d run_target (развернуть динамические типы)

Что-то полезное, чтобы знать, что использование "Frame Variable" для вывода значений переменных гарантирует, что код не будет выполнен.

Ответ 20

Я нашел решение для саморазвивающихся классов (или у вас есть доступ).

Поместите следующее вычисленное свойство в определение класса объектов:

var className: String? {
    return __FILE__.lastPathComponent.stringByDeletingPathExtension
}

Теперь вы можете просто вызвать имя класса на своем объекте так:

myObject.className

Обратите внимание, что это будет работать только в том случае, если ваше определение класса сделано в файле с именем точно, как класс, который вы хотите назвать.

Как обычно бывает в случае , вышеприведенный ответ должен делать это в большинстве случаев. Но в некоторых особых случаях вам может понадобиться найти другое решение.


Если вам нужно имя класса внутри самого класса (файла), вы можете просто использовать эту строку:

let className = __FILE__.lastPathComponent.stringByDeletingPathExtension

Возможно, этот метод помогает некоторым людям там.

Ответ 21

Основываясь на ответах и ​​комментариях, полученных Класом и Кевином Баллардом выше, я бы пошел с:

println(_stdlib_getDemangledTypeName(now).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon?).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(soon!).componentsSeparatedByString(".").last!)

println(_stdlib_getDemangledTypeName(myvar0).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar1).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar2).componentsSeparatedByString(".").last!)
println(_stdlib_getDemangledTypeName(myvar3).componentsSeparatedByString(".").last!)

который будет распечатываться:

"NSDate"
"ImplicitlyUnwrappedOptional"
"Optional"
"NSDate"

"NSString"
"PureSwiftClass"
"Int"
"Double"

Ответ 22

let i: Int = 20


  func getTypeName(v: Any) -> String {
    let fullName = _stdlib_demangleName(_stdlib_getTypeName(i))
    if let range = fullName.rangeOfString(".") {
        return fullName.substringFromIndex(range.endIndex)
    }
    return fullName
}

println("Var type is \(getTypeName(i)) = \(i)")

Ответ 23

Многие из ответов здесь не работают с последним Swift (Xcode 7.1.1 на момент написания).

Текущий способ получения информации - создать Mirror и опросить его. Для имени класса это просто:

let mirror = Mirror(reflecting: instanceToInspect)
let classname:String = mirror.description

Дополнительная информация об объекте также может быть получена из Mirror. Подробнее см. http://swiftdoc.org/v2.1/type/Mirror/.

Ответ 24

Кажется, что нет никакого общего способа печати типа имени произвольного типа значения. Как отмечали другие, для экземпляров классов вы можете печатать value.className, но для примитивных значений появляется, что во время выполнения информация о типе отсутствует.

Например, похоже, что нет способа напечатать: 1.something() и выйти Int для любого значения something. (Вы можете, как сказал другой ответ, использовать i.bridgeToObjectiveC().className, чтобы дать вам подсказку, но __NSCFNumber на самом деле не тип i - то, что он будет преобразован, когда он пересекает границу Objective-C вызов функции.)

Я был бы рад оказаться ошибочным, но похоже, что проверка типов выполняется во время компиляции, и, как и С++ (с отключенным RTTI), большая часть информации о типе отсутствует во время выполнения.

Ответ 25

Swift версия 4:

print("\(type(of: self)) ,\(#function)")
// within a function of a class

Спасибо @Джошуа Дэнс

Ответ 26

Вот как вы получаете строку типа вашего объекта или типа, которая является согласованной и учитывает, к какому модулю принадлежит определение объекта или в который он вложен. Работает в Swift 4.x.

@inline(__always) func typeString(for _type: Any.Type) -> String {
    return String(reflecting: type(of: _type))
}

@inline(__always) func typeString(for object: Any) -> String {
    return String(reflecting: type(of: type(of: object)))
}

struct Lol {
    struct Kek {}
}

// if you run this in playground the results will be something like
typeString(for: Lol.self)    //    __lldb_expr_74.Lol.Type
typeString(for: Lol())       //    __lldb_expr_74.Lol.Type
typeString(for: Lol.Kek.self)//    __lldb_expr_74.Lol.Kek.Type
typeString(for: Lol.Kek())   //    __lldb_expr_74.Lol.Kek.Type

Ответ 27

Свифт 4:

// "TypeName"
func stringType(of some: Any) -> String {
    let string = (some is Any.Type) ? String(describing: some) : String(describing: type(of: some))
    return string
}

// "ModuleName.TypeName"
func fullStringType(of some: Any) -> String {
    let string = (some is Any.Type) ? String(reflecting: some) : String(reflecting: type(of: some))
    return string
}

Использование:

print(stringType(of: SomeClass()))     // "SomeClass"
print(stringType(of: SomeClass.self))  // "SomeClass"
print(stringType(of: String()))        // "String"
print(fullStringType(of: String()))    // "Swift.String"

Ответ 28

Не совсем то, что вам нужно, но вы также можете проверить тип переменной по типам Swift:

let object: AnyObject = 1

if object is Int {
}
else if object is String {
}

Например.

Ответ 29

Xcode 7.3.1, Swift 2.2:

String(instanceToPrint.self).componentsSeparatedByString(".").last

Ответ 30

Swift 3.0, Xcode 8

В следующем коде вы можете запросить экземпляр для своего класса. Вы также можете сравнить два экземпляра, имеющих один класс.

// CREATE pure SWIFT class
class MySwiftClass {
    var someString : String = "default"
    var someInt    : Int = 5
}

// CREATE instances
let firstInstance = MySwiftClass()
let secondInstance = MySwiftClass()
secondInstance.someString = "Donald"
secondInstance.someInt = 24

// INSPECT instances
if type(of: firstInstance) === MySwiftClass.self {
    print("SUCCESS with ===")
} else {
    print("PROBLEM with ===")
}

if type(of: firstInstance) == MySwiftClass.self {
    print("SUCCESS with ==")
} else {
    print("PROBLEM with ==")
}

// COMPARE CLASS OF TWO INSTANCES
if type(of: firstInstance) === type(of: secondInstance) {
    print("instances have equal class")
} else {
    print("instances have NOT equal class")
}