Imagine a class Fruit:
class Fruit: NSObject {
override var description:String {
return super.description
}
}
var apple = Fruit()
var banana = Fruit()
print(apple) // Output: <MyProject.Fruit: 0x7fa719627e00>
print(banana) // Output: <MyProject.Fruit: 0x7fa71962dab0>
Question: How can you mimic this ouput?
I currently have the following:
class Fruit: NSObject {
override var description:String {
print(super.description)
return "<\(NSStringFromClass(self.dynamicType)): 0x\(String(self.hash, radix:16))>"
}
}
Which now outputs the following:
<MyProject.Fruit: 0x7fb958c289a0>
<MyProject.Fruit: 0x7fb958c289a0>
<MyProject.Fruit: 0x7fb958c22df0>
<MyProject.Fruit: 0x7fb958c22df0>
As you can see the output is the same which is what I wanted. Now I am wondering if this is the proper way to mimic it's output or that I am overlooking something as mentioned in the comments below.
Credits: Matt, Martin R and Vacawama
Any subclass of NSObject
inherits the
description
method of NSObject
(which is defined in the NSObjectProtocol
):
class Foo1 : NSObject { }
print(Foo1())
// <MyProject.Foo1: 0x100612fd0>
This "default implementation" prints the class name and the memory
address of the object, see for example
Friday Q&A 2013-01-25: Let's Build NSObject, where it is shown how the Objective-C implementation
could look like:
- (NSString *)description
{
return [NSString stringWithFormat: @"<%@: %p>", [self class], self];
}
The %p
format prints the value of a pointer as a hexadecimal number,
preceded by 0x
.
To mimic that in Swift, we can use
String(reflecting: self.dynamicType)
which returns the fully-qualified class name as a string, and
unsafeAddressOf(self)
which returns a pointer to the storage
of the object.
Example (using square brackets []
to demonstrate that the
overridden method is used):
class Foo2 : NSObject {
override var description : String {
let className = String(reflecting: self.dynamicType)
let address = unsafeAddressOf(self)
return String(format: "[%@: %p]", className, address)
}
}
print(Foo2())
// [MyProject.Foo2: 0x100613310]
class Foo3 : Foo2 { }
print(Foo3())
// [MyProject.Foo3: 0x102000540]
This works for "pure Swift classes" as well, because no Foundation
methods are used:
class Bar : CustomStringConvertible {
var description : String {
let className = String(reflecting: self.dynamicType)
let address = unsafeAddressOf(self)
return String(format: "[%@: %p]", className, address)
}
}
print(Bar())
// [MyProject.Bar: 0x102001200]
Note that (as already mentioned in above comments), the hash value
of an object is not necessarily identical to the memory address.
A simple example is NSArray()
whose hash value is just the number
of elements:
let array = NSArray(objects: 1, 2, 3)
print(unsafeAddressOf(array)) // 0x00000001020011a0
print(array.hashValue) // 3
Update for Swift 3:
class Bar : CustomStringConvertible {
var description : String {
let className = String(reflecting: type(of: self))
let address = Unmanaged.passUnretained(self).toOpaque()
return "[\(className): \(address)]"
}
}
Use String(self.hash, radix:16)
. You might need to prefix the 0x
yourself.