Как напечатать тип или класс переменной в 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!.
30 ответов:
Обновление Сентябрь 2016
Swift 3.0: Use
type(of:), например,type(of: someThing)(посколькуdynamicTypeключевое слово было удалено)Обновление Октября 2015:
я обновил приведенные ниже примеры до нового синтаксиса Swift 2.0 (например,
printlnбыл заменен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.
это то, что вы ищете?
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(который возвращает aString).на самом деле есть несколько способов получить класс, например
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
В 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 self2. Преобразовать тип в строку:
let string : String = "\(type)" //String
SWIFT 3
С последним выпуском Swift 3 мы можем получить довольно описания имен типов через
Stringинициализатор. Например,print(String(describing: type(of: object))). Гдеobjectможет быть переменной экземпляра как массив, словарь,Int, aNSDate, экземпляр пользовательского класса, и т. д.вот мой полный ответ: получить имя класса объекта в виде строки в 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-typedoubleNum = 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чтобы дать вам намек, но__NSCFNumberis не на самом деле типаi-- только то, что он будет преобразован, когда он пересекает границу объективной-C-функции.)Я был бы рад оказаться неправым, но похоже, что проверка типа выполняется во время компиляции, и, как и C++ (с отключенным RTTI), большая часть информации о типе исчезла во время выполнения.
Не совсем то, что вы после, но вы также можете проверить тип переменной на Свифт вроде так:
let object: AnyObject = 1 if object is Int { } else if object is String { }например.
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