What's the equivalent of Obj.C's NSMutableDictionary<Class, Class> in Swift? - swift

What's the equivalent of Obj.C's NSMutableDictionary<Class, Class> in Swift?
I tried:
var dictionary = [AnyClass: AnyClass]()
However this throws the error: Type 'AnyClass' (aka 'AnyObject.Type') does not conform to protocol 'Hashable'
Since there can only be one class per name, we know a given class reference refers to a unique class; there is only one "String" in a given namespace. So why is this not hashable?
I also tried:
var dictionary = NSMutableDictionary<AnyClass, AnyClass>
However this also fails with: Cannot specialize non-generic type 'NSMutableDictionary'
I thought Swift was supposed to be type-safe, but here the compiler is encouraging me to just throw anything into this NSMutableDictionary without type-checking it to make sure it's an AnyClass!
Also, DO NOT lecture me about "You shouldn't be doing that in the first place," because, I am not doing it, it's already like that in some Objective C code that I am required to translate into Swift. I am simply trying to do it in the best possible way—if it means I must resort to a non-type-safe NSMutableDictionary, then so be it, however this seems ridiculous.
Surely I'm missing something here... what am I missing?

The closest you can get in Swift, I discovered, is to do this:
var classToClassMapping = Dictionary<ObjectIdentifier, AnyClass>()
extension Dictionary where Key == ObjectIdentifier, Value == AnyClass {
subscript<T>(keyType: T.Type) -> AnyClass? {
get {
let id = ObjectIdentifier(keyType)
return self[id]
}
set {
let id = ObjectIdentifier(keyType)
self[id] = newValue
}
}
}
classToClassMapping[Yay.self] = NSString.self
if let stringClass = classToClassMapping[Yay.self] as? NSString.Type {
print(stringClass.init(string: "hell yeah"))
}
// Prints "hell yeah"
// Alternative:
switch classToClassMapping[Yay.self] {
case let val as NSString.Type:
print(val.init(string: "yaiirrr boy"))
default:
print("woops")
}
// prints "yaiirrr boy"
Works perfectly for my needs! (Using Swift 5.1 here)

Related

Typecasting with as in Swift

I'm trying to understand of as typecasting.
Reading Type Casting chapter on Apple Documentation, I've two syntax for downcasting (as? and as! operators) but I didn't find anything about as.
So I thought that I should never have used this kink of operator but yesterday when I was typing code with do-try-catch statement, I met this one:
catch let error as NSError {
print(error)
}
Initially, error was type conforms to the Error protocol.
Now using the as NSError casting, it has become an instance of a NSError class.
But my question is: What does as operator do?
It's not a downcasting sure.. Could it be used for "convert" object?
EDIT
I don't think it's a duplicate.
In my case, the error variable, is not a class and doesn't inherit from a super class so I have not a upcasting. It is not even a pattern matching.
I've already read both Swift Blog page and this thread on StackOverflow.
EDIT 2
From Swift Blog
Swift 1.2 separates the notions of guaranteed conversion and forced
conversion into two distinct operators. Guaranteed conversion is still
performed with the as operator, but forced conversion now uses the as!
operator. The ! is meant to indicate that the conversion may fail.
This way, you know at a glance which conversions may cause the program
to crash.
The text above doesn't work for me because if I tried to use the as! operator instead of as, compiler complain me.
EDIT 3
Even in Using Swift with Cocoa and Obj-C documentation they use the let-as? syntax for checking and casting to a protocol.
So, why in my case, I can't use it?
First of all, as suggested in the dasblinkenlight's comment, your code snippet is not using a type-casting-operator. Check the syntax of do-statement­ and you can find these:
catch-clause → catch­ pattern­opt ­where-clause­opt ­code-block­
pattern → value-binding-pattern­
value-binding-pattern → var ­pattern |­ let ­pattern­
pattern → type-casting-pattern­
type-casting-pattern → is-pattern­ | as-pattern­
as-pattern → pattern ­as ­type­
So, your EDIT 2 has no meaning, there are no syntax accepting as! in catch-clause.
But this code (using type-casting-operator) works, so I try to explain how to use as-casting.
enum MyError: Error {
case bad
//...
}
let error: Error = MyError.bad
let nsError = error as NSError
As shown in the linked article in the EI Captain v2.0's comment, as-casting is used for Guaranteed conversion. I have collected some use cases of such conversions.
Upcasting
class Animal {}
class Dog: Animal {}
let d = Dog()
d as Animal // upcast succeeds
As shown in the article, upcasting always succeeds, so you can use as.
Specifying literal type
let byte = 123 as UInt8
let ch = "a" as UnicodeScalar
In Swift, literals are typeless, so you can use as to specify the types of literals
In case Swift can infer the type of the literal, you can omit such as-casting:
let byte: UInt8 = 123
let ch: UnicodeScalar = "a"
Disambiguating overloaded methods
class MyClass {
func aMethod(_ arg: String) {
print(arg)
}
func aMethod(_ arg: Int) {
print("\"\(arg)\"")
}
}
let obj = MyClass()
let theFunc = obj.aMethod as (String)->Void
theFunc("abc") //->abc
Always-succeeds bridging
let str: String = "a String"
let nsStr = str as NSString
let intArr: [Int] = [1,2,3]
let nsArr = intArr as NSArray
The example let nsError = error as NSError is included in this category, and you need to read this article carefully, to understand why this is an always-succeeds bridging.
For your EDIT 3.
You may need to distinguish these two syntaxes:
let a: Any = 1
//Using if-let -- Optional binding, `(a as? Int)` is an expression using type-casting-operator which generates an Optional result
if let intA = (a as? Int) {
print("\(intA) is Int")
}
//Using if-case -- pattern matching, `(let intA as Int)` is a pattern using as-pattern
if case (let intA as Int) = a {
print("\(intA) is Int")
}
As already noted, catch leads a pattern, and you cannot use as? in pattern.
as
Use as for types that Apple has done some work to handle the conversion in the background. These are usually Foundation types that Apple bridged into Swift and want you to have a quick way to convert back and forth from their ObjC equivalents, for example:
String <-> NSString
URL <-> NSURL
Array <-> NSArray
Data <-> NSData
These casts always succeed and Xcode will warn you if you use as? or as!. In your specific case, Apple has done some meddling in the background to make the Error protocol and NSError to be castable to/from each other.
as!
Use as! when you know the object is castable to another type. as! will crash your app if the object is not castable (for example, when sender is actually a UITextField)
let button = sender as! UIButton // you are sure that the sender is always
// a UIButton or your app will crash
as?
Use as? when you not sure if the object is castable to the other type. In practice, this should be your preferred method and you should optional binding to check for success. as? produces nil if the object is not castable:
// Exit the function if the sender is not a UIButton
guard let sender = sender as? UIButton else {
return
}
// Only execute the block if the sender is UIButton
if let button = sender as? UIButton {
// ...
}

Can a condition be used to determine the type of a generic?

I will first explain what I'm trying to do and how I got to where I got stuck before getting to the question.
As a learning exercise for myself, I took some problems that I had already solved in Objective-C to see how I can solve them differently with Swift. The specific case that I got stuck on is a small piece that captures a value before and after it changes and interpolates between the two to create keyframes for an animation.
For this I had an object Capture with properties for the object, the key path and two id properties for the values before and after. Later, when interpolating the captured values I made sure that they could be interpolated by wrapping each of them in a Value class that used a class cluster to return an appropriate class depending on the type of value it wrapped, or nil for types that wasn't supported.
This works, and I am able to make it work in Swift as well following the same pattern, but it doesn't feel Swift like.
What worked
Instead of wrapping the captured values as a way of enabling interpolation, I created a Mixable protocol that the types could conform to and used a protocol extension for when the type supported the necessary basic arithmetic:
protocol SimpleArithmeticType {
func +(lhs: Self, right: Self) -> Self
func *(lhs: Self, amount: Double) -> Self
}
protocol Mixable {
func mix(with other: Self, by amount: Double) -> Self
}
extension Mixable where Self: SimpleArithmeticType {
func mix(with other: Self, by amount: Double) -> Self {
return self * (1.0 - amount) + other * amount
}
}
This part worked really well and enforced homogeneous mixing (that a type could only be mixed with its own type), which wasn't enforced in the Objective-C implementation.
Where I got stuck
The next logical step, and this is where I got stuck, seemed to be to make each Capture instance (now a struct) hold two variables of the same mixable type instead of two AnyObject. I also changed the initializer argument from being an object and a key path to being a closure that returns an object ()->T
struct Capture<T: Mixable> {
typealias Evaluation = () -> T
let eval: Evaluation
let before: T
var after: T {
return eval()
}
init(eval: Evaluation) {
self.eval = eval
self.before = eval()
}
}
This works when the type can be inferred, for example:
let captureInt = Capture {
return 3.0
}
// > Capture<Double>
but not with key value coding, which return AnyObject:\
let captureAnyObject = Capture {
return myObject.valueForKeyPath("opacity")!
}
error: cannot invoke initializer for type 'Capture' with an argument list of type '(() -> _)'
AnyObject does not conform to the Mixable protocol, so I can understand why this doesn't work. But I can check what type the object really is, and since I'm only covering a handful of mixable types, I though I could cover all the cases and return the correct type of Capture. Too see if this could even work I made an even simpler example
A simpler example
struct Foo<T> {
let x: T
init(eval: ()->T) {
x = eval()
}
}
which works when type inference is guaranteed:
let fooInt = Foo {
return 3
}
// > Foo<Int>
let fooDouble = Foo {
return 3.0
}
// > Foo<Double>
But not when the closure can return different types
let condition = true
let foo = Foo {
if condition {
return 3
} else {
return 3.0
}
}
error: cannot invoke initializer for type 'Foo' with an argument list of type '(() -> _)'
I'm not even able to define such a closure on its own.
let condition = true // as simple as it could be
let evaluation = {
if condition {
return 3
} else {
return 3.0
}
}
error: unable to infer closure type in the current context
My Question
Is this something that can be done at all? Can a condition be used to determine the type of a generic? Or is there another way to hold two variables of the same type, where the type was decided based on a condition?
Edit
What I really want is to:
capture the values before and after a change and save the pair (old + new) for later (a heterogeneous collection of homogeneous pairs).
go through all the collected values and get rid of the ones that can't be interpolated (unless this step could be integrated with the collection step)
interpolate each homogeneous pair individually (mixing old + new).
But it seems like this direction is a dead end when it comes to solving that problem. I'll have to take a couple of steps back and try a different approach (and probably ask a different question if I get stuck again).
As discussed on Twitter, the type must be known at compile time. Nevertheless, for the simple example at the end of the question you could just explicitly type
let evaluation: Foo<Double> = { ... }
and it would work.
So in the case of Capture and valueForKeyPath: IMHO you should cast (either safely or with a forced cast) the value to the Mixable type you expect the value to be and it should work fine. Afterall, I'm not sure valueForKeyPath: is supposed to return different types depending on a condition.
What is the exact case where you would like to return 2 totally different types (that can't be implicitly casted as in the simple case of Int and Double above) in the same evaluation closure?
in my full example I also have cases for CGPoint, CGSize, CGRect, CATransform3D
The limitations are just as you have stated, because of Swift's strict typing. All types must be definitely known at compile time, and each thing can be of only one type - even a generic (it is resolved by the way it is called at compile time). Thus, the only thing you can do is turn your type into into an umbrella type that is much more like Objective-C itself:
let condition = true
let evaluation = {
() -> NSObject in // *
if condition {
return 3
} else {
return NSValue(CGPoint:CGPointMake(0,1))
}
}

Convert or cast object to string

how can i convert any object type to a string?
let single_result = results[i]
var result = ""
result = single_result.valueForKey("Level")
now i get the error: could not assign a value of type any object to a value of type string.
and if i cast it:
result = single_result.valueForKey("Level") as! String
i get the error:
Could not cast value of type '__NSCFNumber' (0x103215cf0) to 'NSString' (0x1036a68e0).
How can i solve this issue?
You can't cast any random value to a string. A force cast (as!) will fail if the object can't be cast to a string.
If you know it will always contain an NSNumber then you need to add code that converts the NSNumber to a string. This code should work:
if let result_number = single_result.valueForKey("Level") as? NSNumber
{
let result_string = "\(result_number)"
}
If the object returned for the "Level" key can be different object types then you'll need to write more flexible code to deal with those other possible types.
Swift arrays and dictionaries are normally typed, which makes this kind of thing cleaner.
I'd say that #AirSpeedVelocity's answer (European or African?) is the best. Use the built-in toString function. It sounds like it works on ANY Swift type.
EDIT:
In Swift 3, the answer appears to have changed. Now, you want to use the String initializer
init(describing:)
Or, to use the code from the question:
result = single_result.valueForKey("Level")
let resultString = String(describing: result)
Note that usually you don't want valueForKey. That is a KVO method that will only work on NSObjects. Assuming single_result is a Dictionary, you probably want this syntax instead:
result = single_result["Level"]
This is the documentation for the String initializer provided here.
let s = String(describing: <AnyObject>)
Nothing else is needed. This works for a diverse range of objects.
The toString function accepts any type and will always produce a string.
If it’s a Swift type that implements the Printable protocol, or has overridden NSObject’s description property, you’ll get whatever the .description property returns. In the case of NSNumber, you’ll get a string representation of the number.
If it hasn’t, you’ll get a fairly unhelpful string of the class name plus the memory address. But most standard classes, including NSNumber, will produce something sensible.
import Foundation
class X: NSObject {
override var description: String {
return "Blah"
}
}
let x: AnyObject = X()
toString(x) // return "Blah"
"\(x)" // does the same thing but IMO is less clear
struct S: Printable {
var description: String {
return "asdf"
}
}
// doesn't matter if it's an Any or AnyObject
let s: Any = S()
toString(s) // reuturns "asdf"
let n = NSNumber(double: 123.45)
toString(n) // returns "123.45"
n.stringValue // also works, but is specific to NSNumber
(p.s. always use toString rather than testing for Printable. For one thing, String doesn’t conform to Printable...)
toString() doesn't seem to exist in Swift 3 anymore.
Looks like there's a failable initializer that will return the passed in value's description.
init?(_ description: String)
Docs here https://developer.apple.com/reference/swift/string/1540435-init

Swift: Casting collections, and creating custom convertible protocols

Consider this Person class, which simply implements StringLiteralConvertible and assigns the string literal to name:
class Person : StringLiteralConvertible {
var name : String?
typealias StringLiteralType = String
required init(stringLiteral value: StringLiteralType) {
println("stringLiteral \(value)")
name = value
}
typealias ExtendedGraphemeClusterLiteralType = String
required init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
println("extendedGraphemeClusterLiteral \(value)")
name = value
}
typealias UnicodeScalarLiteralType = Character
required init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
println("unicodeScalarLiteral \(value)")
name = "\(value)"
}
}
This allows me to create a Person instance using a string:
let aaron : Person = "Aaron"
I can even cast an array of Persons from an array of strings:
let names = ["John", "Jane"] as [Person]
However this only works with string literals. If I use a string variable, it fails:
let aaronString = "Aaron"
let aaron : Person = aaronString
// Error: 'NSString' is not a subtype of 'Person'
Similarly, trying to cast an array of non-literal strings fails:
let nameStrings = ["John", "Jane"]
let people : [Person] = nameStrings
// Error: 'String' is not identical to 'Person'
I have three questions:
Is there another protocol I can implement to cast a non-literal string to a Person? I'd like to do this so I can cast entire collections to convert the objects.
If no to #1, is map + an initializer the best way to perform the conversion myself?
let nameStrings = ["John", "Jane"]
let people = nameStrings.map{Person(name: $0)}
If yes to #1, is there a similar approach I can use to specify an approach to convert two objects which are unrelated in hierarchy? That is, can I work around this error without an initializer?
let rikerPerson : Person = "Riker"
let rikerEmployee = rikerPerson as Employee
// Error: 'Person' is not convertible to 'Employee'
What you are describing as “casting” isn’t really casting (in the way that, say, s = “fred”; ns = s as NSString is, or that casts in C++ are).
let names = ["John", "Jane"] as [Person]
is just another a way of writing:
let names: [Person] = ["John", "Jane"]
that is, a way of telling Swift which of the many possible versions of StringLiteralConvertible to use (and not the one for String, which is the default).
Put it another way – your as is fulfilling a similar function to the as in this snippet that disambiguates two overloaded functions that differ only by return type:
func f() -> String { return "foo" }
func f() -> Int { return 42 }
let i = f() as Int // i will be 42
let s = f() as String // s will be “foo"
No “conversion” is going on here – the as is just being used to disambiguate which f Swift calls. It’s the same with which init(stringLiteral:) is chosen.
Definitely (but only if you put a space between map and the { } ;-).
If you’re concerned about the waste of converting it all to an array just to do some other thing with it, check out lazy(a).map
Nope. In the betas, there used to be a __conversion() -> T method you could implement to do “casts” like this on your own classes – or more importantly, allowed you to pass your Person class into a function that took an Employee argument and have it be converted implicitly. But that got disappeared. Generally that kind of implicit conversion is antithetical to Swift’s style, except in rare cases (Obj-C and C interop, and implicit wrapping in optionals, being the main ones). You have to write an init for Employee that takes a Person (or some class or protocol that Person conforms to), and then call it.

How do I print the type or class of a variable in Swift?

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!.
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.
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.
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>"
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
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.
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"
You can still access the class, through className (which returns a String).
There are actually several ways to get the class, for example classForArchiver, classForCoder, classForKeyedArchiver (all return AnyClass!).
You can't get the type of a primitive (a primitive is not a class).
Example:
var ivar = [:]
ivar.className // __NSDictionaryI
var i = 1
i.className // error: 'Int' does not have a member named 'className'
If you want to get the type of a primitive, you have to use bridgeToObjectiveC(). Example:
var i = 1
i.bridgeToObjectiveC().className // __NSCFNumber
You can use reflect to get information about object.
For example name of object class:
var classname = reflect(now).summary
Xcode 8 Swift 3.0 use type(of:)
let className = "\(type(of: instance))"
I had luck with:
let className = NSStringFromClass(obj.dynamicType)
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:
diccionary is of type Dictionary
array is of type Array
numInt is of type Int
numFloat is of type CGFloat
numDouble is of type Double
classOne is of type: ClassOne
classTwo is of type: ClassTwo
now is of type: Date
lbl is of type: UILabel
In Xcode 8, Swift 3.0
Steps:
1. Get the Type:
Option 1:
let type : Type = MyClass.self //Determines Type from Class
Option 2:
let type : Type = type(of:self) //Determines Type from self
2. Convert Type to String:
let string : String = "\(type)" //String
In Swift 3.0, you can use type(of:), as dynamicType keyword has been removed.
To get a type of object or class of object in Swift, you must need to use a type(of: yourObject)
type(of: yourObject)
When using Cocoa (not CocoaTouch), you can use the className property for objects that are subclasses of NSObject.
println(now.className)
This property is not available for normal Swift objects, which aren't subclasses of NSObject (and in fact, there is no root id or object type in Swift).
class Person {
var name: String?
}
var p = Person()
println(person.className) // <- Compiler error
In CocoaTouch, at this time there is not a way to get a string description of the type of a given variable. Similar functionality also does not exist for primitive types in either Cocoa or CocoaTouch.
The Swift REPL is able to print out a summary of values including its type, so it is possible this manner of introspection will be possible via an API in the future.
EDIT: dump(object) seems to do the trick.
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'
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.
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;
}
In the latest XCode 6.3 with Swift 1.2, this is the only way I found:
if view.classForCoder.description() == "UISegment" {
...
}
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.
Swift version 4:
print("\(type(of: self)) ,\(#function)")
// within a function of a class
Thanks #Joshua Dance
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.
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.
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"
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 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
}
Usage:
print(stringType(of: SomeClass())) // "SomeClass"
print(stringType(of: SomeClass.self)) // "SomeClass"
print(stringType(of: String())) // "String"
print(fullStringType(of: String())) // "Swift.String"
There appears to be no generic way to print the type name of an arbitrary value's type. As others have noted, for class instances you can print value.className but for primitive values it appears that at runtime, the type information is gone.
For instance, it looks as if there's not a way to type: 1.something() and get out Int for any value of something. (You can, as another answer suggested, use i.bridgeToObjectiveC().className to give you a hint, but __NSCFNumber is not actually the type of i -- just what it will be converted to when it crosses the boundary of an Objective-C function call.)
I would be happy to be proven wrong, but it looks like the type checking is all done at compile time, and like C++ (with RTTI disabled) much of the type information is gone at runtime.
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
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.
Xcode 7.3.1, Swift 2.2:
String(instanceToPrint.self).componentsSeparatedByString(".").last