Как напечатать тип или класс переменной в 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!.

938   30  

30 ответов:

Обновление Сентябрь 2016

Swift 3.0: Use 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 есть искаженное имя типа переменной. запись в блоге Эвана Свика помогает расшифровать эти строки:

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

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

Edit:новая 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.

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

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

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

обновление: Пожалуйста, обратите внимание, что это больше не работает с Beta05

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>"

мой текущий 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, {  == "." })
    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.

начиная с 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"

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

на самом деле есть несколько способов получить класс, например classForArchiver,classForCoder,classForKeyedArchiver (все вернуть 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

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

var classname = reflect(now).summary

Мне повезло с:

let className = NSStringFromClass(obj.dynamicType)

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

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

В 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

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

SWIFT 3

С последним выпуском Swift 3 мы можем получить довольно описания имен типов через String инициализатор. Например,print(String(describing: type(of: object))). Где objectможет быть переменной экземпляра как массив, словарь,Int, a 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()

и выход было:

  • diccionary имеет тип словарь
  • массив имеет тип Array
  • numInt имеет тип Int
  • numFloat имеет тип CGFloat
  • numDouble имеет тип Double
  • classOne имеет тип: ClassOne
  • classTwo имеет тип: ClassTwo
  • теперь имеет тип: дата
  • lbl имеет тип: UILabel

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

println(now.className)

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

class Person {
    var name: String?
}

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

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

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

EDIT:dump(object) кажется, сделать трюк.

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

однако я нашел способ, которым вы можете получить имя класса 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 в консоли.

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

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

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

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

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

fr v -d r shipDate

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

(DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940

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

Frame Variable (печать переменной кадра)-d run_target (расширение динамического типа)

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

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

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

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

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

myObject.className

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

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


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

let className = __FILE__.lastPathComponent.stringByDeletingPathExtension

может быть, этот способ помогает некоторым людям там.

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

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"
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)")

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

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

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

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

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

doubleNum = 30.1

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

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

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

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

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

Не совсем то, что вы после, но вы также можете проверить тип переменной на Свифт вроде так:

let object: AnyObject = 1

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

например.

Xcode 7.3.1, Swift 2.2:

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

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

Swift version 4:

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

Спасибо @Joshua Dance

Это, как вы получаете строку типа объект или тип что это последовательный и принимает во внимание, к которому модуль определение объекта принадлежит или вложенными. Работает в 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

это также удобно при проверке, является ли объект типом класса:

if someObject is SomeClass {
    //someObject is a type of SomeClass
}

Comments

    Ничего не найдено.