With ARC, I can just set all of an object's strong references to nil
to deallocate it.
With an UnsafePointer
or UnsafeMutablePointer
, I need to manage its memory explicitly:
let buffer = sizeof(Int8) * 4
var ptr = UnsafeMutablePointer<Void>.alloc(buffer)
defer {
ptr.destroy()
ptr.dealloc(someVal)
ptr = nil
}
But the documentation is ambiguous for AutoreleasingUnsafeMutablePointer
objects. I cannot explicitly call destroy
or dealloc
on a AutoreleasingUnsafeMutablePointer
.
var ptr: AutoreleasingUnsafeMutablePointer<Void> = nil
defer {
ptr = nil
}
// assign something to ptr
The name implies that it is autoreleased after it falls out of scope, but do I need to set a AutoreleasingUnsafeMutablePointer
to nil
in order for it to be autoreleased?
Here's an example where I use an AutoreleasingUnsafeMutablePointer
to get a list of all of the classes currently loaded by the runtime. Note that when invoking the power of the Objective-C runtime some functions require a AutoreleasingUnsafeMutablePointer
rather than just a UnsafeMutablePointer
:
var numClasses: Int32 = 0
var allClasses: AutoreleasingUnsafeMutablePointer<AnyClass?> = nil
defer {
allClasses = nil // is this required?
}
numClasses = objc_getClassList(nil, 0)
if numClasses > 0 {
var ptr = UnsafeMutablePointer<AnyClass>.alloc(Int(numClasses))
defer {
ptr.destroy()
ptr.dealloc(Int(numClasses))
ptr = nil
}
allClasses = AutoreleasingUnsafeMutablePointer<AnyClass?>.init(ptr)
numClasses = objc_getClassList(allClasses, numClasses)
for i in 0 ..< numClasses {
if let currentClass: AnyClass = allClasses[Int(i)] {
print("\(currentClass)")
}
}
}
You don't need to set it to nil
. It is supposed to be constructed from an autoreleased pointer (assuming it was constructed correctly, it will release itself). At the same time, don't hold onto it past the current stack frame. The AutoreleasingUnsafeMutablePointer
does not keep the object alive. When the enclosing autorelease pool is popped, the wrapped object will be released and probably deallocated. Like the name says: it is unsafe.
Avoid problems by never creating AutoreleasingUnsafeMutablePointer
yourself in Swift (edit: except when it's really an UnsafeMutablePointer and the C header import has made a mistake, see below). If you're using it correctly, it should be transparent glue between Swift's inout
and an Objective-C return-by-pointer parameter.
You generally create a var
matching the contained type and pass it in by inout
.
e.g. if you want to call the function:
func someFunction(obj: AutoreleasingUnsafeMutablePointer<AnyObject?>)
then you invoke it like this:
var myObject: AnyObject? = nil
someFunction(&AnyObject)
and everything will work out.
I'm not aware of any other situation where you should hold an AutoreleasingUnsafeMutablePointer
. I don't think you should be manually constructing one at all on the Swift side except as nil
. It is precariously difficult in Swift to construct an AutoreleasingUnsafeMutablePointer
with non-nil
contents since the only way to autorelease is using Unmanaged
.
Responding to your update...
The objc_getClassList
function signature is a glitch in Swift's automatic C importing. It incorrectly assumes that a Class *
parameter should be imported as AutoreleasingUnsafeMutablePointer<AnyObject?>
. You really just need an UnsafeMutablePointer
which you can get from an array:
var allClasses = Array<AnyClass?>(count: Int(objc_getClassList(nil, 0)), repeatedValue: nil)
allClasses.withUnsafeMutableBufferPointer { (inout bp: UnsafeMutableBufferPointer<AnyClass?>) in
objc_getClassList(AutoreleasingUnsafeMutablePointer(bp.baseAddress), Int32(allClasses.count))
}