Reputation: 49435
Is there a way to print the runtime type of a variable in swift? For example:
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
In the example above, I'm looking for a way to show that the variable "soon" is of type ImplicitlyUnwrappedOptional<NSDate>
, or at least NSDate!
.
Upvotes: 367
Views: 269658
Reputation: 5142
SWIFT 5
With the latest release of Swift 3 we can get pretty descriptions of type names through the String
initializer. Like, for example print(String(describing: type(of: object)))
. Where object
can be an instance variable like array, a dictionary, an Int
, a NSDate
, an instance of a custom class, etc.
Here is my complete answer: Get class name of object as string in Swift
That question is looking for a way to getting the class name of an object as string but, also i proposed another way to getting the class name of a variable that isn't subclass of NSObject
. Here it is:
class Utility{
class func classNameAsString(obj: Any) -> String {
//prints more readable results for dictionaries, arrays, Int, etc
return String(describing: type(of: obj))
}
}
I made a static function which takes as parameter an object of type Any
and returns its class name as String
:) .
I tested this function with some variables like:
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()
and the output was:
Upvotes: 12
Reputation: 8627
// "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"
Upvotes: 4
Reputation: 1372
To get a type of object or class of object in Swift, you must need to use a type(of: yourObject)
type(of: yourObject)
Upvotes: 7
Reputation: 409
This is how you get a type string of your object or Type which is consistent and takes into account to which module the object definition belongs to or nested in. Works in 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
Upvotes: 2
Reputation: 4038
Swift version 4:
print("\(type(of: self)) ,\(#function)")
// within a function of a class
Thanks @Joshua Dance
Upvotes: 4
Reputation: 10512
The top answer doesn't have a working example of the new way of doing this using type(of:
. So to help rookies like me, here is a working example, taken mostly from Apple's docs here - 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'
Upvotes: 5
Reputation: 51421
Another important aspect that influences the class name returned from String(describing: type(of: self))
is Access Control.
Consider the following example, based on Swift 3.1.1, Xcode 8.3.3 (July 2017)
func printClassNames() {
let className1 = SystemCall<String>().getClassName()
print(className1) // prints: "SystemCall<String>"
let className2 = DemoSystemCall().getClassName()
print(className2) // prints: "DemoSystemCall"
// private class example
let className3 = PrivateDemoSystemCall().getClassName()
print(className3) // prints: "(PrivateDemoSystemCall in _0FC31E1D2F85930208C245DE32035247)"
// fileprivate class example
let className4 = FileprivateDemoSystemCall().getClassName()
print(className4) // prints: "(FileprivateDemoSystemCall in _0FC31E1D2F85930208C245DE32035247)"
}
class SystemCall<T> {
func getClassName() -> String {
return String(describing: type(of: self))
}
}
class DemoSystemCall: SystemCall<String> { }
private class PrivateDemoSystemCall: SystemCall<String> { }
fileprivate class FileprivateDemoSystemCall: SystemCall<String> { }
As you can see, all classes in this example have different levels of access control which influence their String
representation. In case the classes have private
or fileprivate
access control levels, Swift seems to append some kind of identifier related to the "nesting" class of the class in question.
The result for both PrivateDemoSystemCall
and FileprivateDemoSystemCall
is that the same identifier is appended because they both are nested in the same parent class.
I have not yet found a way to get rid of that, other than some hacky replace or regex function.
Just my 2 cents.
Upvotes: 0
Reputation: 465
Please have a look at the below code snippet and let me know if you are looking for something like below or not.
var now = NSDate()
var soon = now.addingTimeInterval(5.0)
var nowDataType = Mirror(reflecting: now)
print("Now is of type: \(nowDataType.subjectType)")
var soonDataType = Mirror(reflecting: soon)
print("Soon is of type: \(soonDataType.subjectType)")
Upvotes: 0
Reputation: 7930
Swift 3.0, Xcode 8
With the following code you can ask an instance for its class. You can also compare two instances, wether having the same class.
// 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")
}
Upvotes: 1
Reputation: 1876
This is also handy when checking if an object is a type of a class:
if someObject is SomeClass {
//someObject is a type of SomeClass
}
Upvotes: 0
Reputation: 37349
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>"
Upvotes: 41
Reputation: 22773
Update September 2016
Swift 3.0: Use type(of:)
, e.g. type(of: someThing)
(since the dynamicType
keyword has been removed)
Update October 2015:
I updated the examples below to the new Swift 2.0 syntax (e.g. println
was replaced with print
, toString()
is now String()
).
From the Xcode 6.3 release notes:
@nschum points out in the comments that the Xcode 6.3 release notes show another way:
Type values now print as the full demangled type name when used with println or string interpolation.
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)")
Which outputs:
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>
Update for Xcode 6.3:
You can use the _stdlib_getDemangledTypeName()
:
print( "TypeName0 = \(_stdlib_getDemangledTypeName(myvar0))")
print( "TypeName1 = \(_stdlib_getDemangledTypeName(myvar1))")
print( "TypeName2 = \(_stdlib_getDemangledTypeName(myvar2))")
print( "TypeName3 = \(_stdlib_getDemangledTypeName(myvar3))")
and get this as output:
TypeName0 = NSString
TypeName1 = __lldb_expr_26.PureSwiftClass
TypeName2 = Swift.Int
TypeName3 = Swift.String
Original answer:
Prior to Xcode 6.3 _stdlib_getTypeName
got the mangled type name of a variable. Ewan Swick's blog entry helps to decipher these strings:
e.g. _TtSi
stands for Swift's internal Int
type.
Mike Ash has a great blog entry covering the same topic.
Upvotes: 408
Reputation: 17725
let type : Type = MyClass.self //Determines Type from Class
let type : Type = type(of:self) //Determines Type from self
let string : String = "\(type)" //String
Upvotes: 10
Reputation: 1681
Xcode 8 Swift 3.0 use type(of:)
let className = "\(type(of: instance))"
Upvotes: 15
Reputation: 565
In Swift 3.0, you can use type(of:)
, as dynamicType
keyword has been removed.
Upvotes: 9
Reputation: 8749
Xcode 7.3.1, Swift 2.2:
String(instanceToPrint.self).componentsSeparatedByString(".").last
Upvotes: 1
Reputation: 6504
Many of the answers here do not work with the latest Swift (Xcode 7.1.1 at time of writing).
The current way of getting the information is to create a Mirror
and interrogate that. For the classname it is as simple as:
let mirror = Mirror(reflecting: instanceToInspect)
let classname:String = mirror.description
Additional information about the object can also be retrieved from the Mirror
. See http://swiftdoc.org/v2.1/type/Mirror/ for details.
Upvotes: 4
Reputation: 45210
Edit: A new toString
function has been introduced in Swift 1.2 (Xcode 6.3).
You can now print the demangled type of any type using .self
and any instance using .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
Try calling YourClass.self
and yourObject.dynamicType
.
Reference: https://devforums.apple.com/thread/227425.
Upvotes: 46
Reputation: 1029
Not exactly what you are after, but you can also check the type of the variable against Swift types like so:
let object: AnyObject = 1
if object is Int {
}
else if object is String {
}
For example.
Upvotes: 1
Reputation: 167
In the latest XCode 6.3 with Swift 1.2, this is the only way I found:
if view.classForCoder.description() == "UISegment" {
...
}
Upvotes: 4
Reputation: 1935
As of Xcode 6.3 with Swift 1.2, you can simply convert type values into the full 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"
Upvotes: 18
Reputation: 313
I found this solution which hopefully might work for someone else. I created a class method to access the value. Please bear in mind this will work for NSObject subclass only. But at least is a clean and tidy solution.
class var className: String!{
let classString : String = NSStringFromClass(self.classForCoder())
return classString.componentsSeparatedByString(".").last;
}
Upvotes: 4
Reputation: 31
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)")
Upvotes: 3
Reputation: 2701
Based on the answers and comments given by Klass and Kevin Ballard above, I would go with:
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!)
which will print out:
"NSDate"
"ImplicitlyUnwrappedOptional"
"Optional"
"NSDate"
"NSString"
"PureSwiftClass"
"Int"
"Double"
Upvotes: 3
Reputation: 21478
I've found a solution for self-developed classes (or such you have access to).
Place the following computed property within your objects class definition:
var className: String? {
return __FILE__.lastPathComponent.stringByDeletingPathExtension
}
Now you can simply call the class name on your object like so:
myObject.className
Please note that this will only work if your class definition is made within a file that is named exactly like the class you want the name of.
As this is commonly the case the above answer should do it for most cases. But in some special cases you might need to figure out a different solution.
If you need the class name within the class (file) itself you can simply use this line:
let className = __FILE__.lastPathComponent.stringByDeletingPathExtension
Maybe this method helps some people out there.
Upvotes: 3
Reputation: 1506
I've tried some of the other answers here but milage seems to very on what the underling object is.
However I did found a way you can get the Object-C class name for an object by doing the following:
now?.superclass as AnyObject! //replace now with the object you are trying to get the class name for
Here is and example of how you would use it:
let now = NSDate()
println("what is this = \(now?.superclass as AnyObject!)")
In this case it will print NSDate in the console.
Upvotes: 4
Reputation: 651
My current Xcode is Version 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).")
}
}
Output:
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.
Upvotes: 23
Reputation: 26903
I had luck with:
let className = NSStringFromClass(obj.dynamicType)
Upvotes: 13
Reputation: 897
Is this what you're looking for?
println("\(object_getClassName(now))");
It prints "__NSDate"
UPDATE: Please note this no longer seems to work as of Beta05
Upvotes: 30
Reputation: 75057
In lldb as of beta 5, you can see the class of an object with the command:
fr v -d r shipDate
which outputs something like:
(DBSalesOrderShipDate_DBSalesOrderShipDate_ *) shipDate = 0x7f859940
The command expanded out means something like:
Frame Variable
(print a frame variable) -d run_target
(expand dynamic types)
Something useful to know is that using "Frame Variable" to output variable values guarantees no code is executed.
Upvotes: 3