Swift’s deinit
support makes it simple to track when instances deallocate. You can throw a print statement in there and watch when things go away.
deinit { print("Deallocating instance") }
If you’re going to watch object lifecycles, it helps to track which object you’re dealing with. Swift value types don’t really have identifiers. There’s no “notion of identity” for structs, enums, functions, and tuples. For classes, though, you can use ObjectIdentifier
to fetch a unique identifier.
class MyClass { init () { print("Creating instance", ObjectIdentifier(self).uintValue) } deinit { print("Deallocating instance", ObjectIdentifier(self).uintValue) } }
Handy for tracking things. Here’s an example that goes through ridiculous loops in order to force an item past its natural life:
struct HandlerStruct { let ptr: UnsafeMutablePointer<Void> func unsafeFunc() { let f = Unmanaged<MyClass> .fromOpaque(COpaquePointer(ptr)) .takeRetainedValue() print(f.message) } } class MyClass { let message = "Got here" func test() { let ptr = UnsafeMutablePointer<Void>(Unmanaged<MyClass> .passRetained(self).toOpaque()) let b = HandlerStruct(ptr: ptr) let delayTime = dispatch_time( DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC))) dispatch_after(delayTime, dispatch_get_main_queue()) { b.unsafeFunc() } } init () { print("Creating instance", ObjectIdentifier(self).uintValue) } deinit { print("Deallocating instance", ObjectIdentifier(self).uintValue) } } MyClass().test() CFRunLoopRun()
If you switch the retained code to unretained, you’ll see the deallocation followed by the crash-and-burn when the now-deallocated instance is accessed by the handler.
Thanks Josh W and Mike Ash
One Comment
Can you explain the code a bit. I understand what you’re trying to demonstrate, but having trouble with understanding what the code is doing.