Skip to content

Unmanaged in Swift

Unmanaged is a struct type that is used to manage the memory of instances that have manual memory management, such as Core Foundation APIs.

In Swift, memory management is typically handled automatically through Automatic Refereces Counting (ARC). However, when dealing with Core Foundation or C APIs, you need to manage memory manually.

Unmanaged struct type lets you create, pass, and return unmanaged objects without transfering ownership, meaning ARC won't release them automatically.

passRetained & takeRetainedValue

Unmanaged.passRetained(obj) static method creates an unmanaged reference to the object and increases its retain account by one.

Conversely, takeRetainedValue() instance method of an Unmanaged instance returns a managed reference to the object and decreases its retain count by one.

For example:

swift
import Foundation

class MyClass {
    var value: Int
    init(value: Int) {
        self.value = value
    }
}

func cFunction(_ obj: UnsafeMutableRawPointer) {
    let unmanaged = Unmanaged<MyClass>.fromOpaque(obj)
    let myObject = unmanaged.takeRetainedValue()
    print("takeRetainedValue:\(CFGetRetainCount(myObject))") 
    // takeRetainedValue() -> retainAccount - 1
    // myObject -> retainAccount + 1
}

func callCFunction() {
    let myObject = MyClass(value: 42)
    print("create:\(CFGetRetainCount(myObject))")
    let ptr = Unmanaged.passRetained(myObject).toOpaque()
    print("ptr:\(ptr)")
    print("passRetained:\(CFGetRetainCount(myObject))")
    cFunction(ptr)
}

callCFunction()
import Foundation

class MyClass {
    var value: Int
    init(value: Int) {
        self.value = value
    }
}

func cFunction(_ obj: UnsafeMutableRawPointer) {
    let unmanaged = Unmanaged<MyClass>.fromOpaque(obj)
    let myObject = unmanaged.takeRetainedValue()
    print("takeRetainedValue:\(CFGetRetainCount(myObject))") 
    // takeRetainedValue() -> retainAccount - 1
    // myObject -> retainAccount + 1
}

func callCFunction() {
    let myObject = MyClass(value: 42)
    print("create:\(CFGetRetainCount(myObject))")
    let ptr = Unmanaged.passRetained(myObject).toOpaque()
    print("ptr:\(ptr)")
    print("passRetained:\(CFGetRetainCount(myObject))")
    cFunction(ptr)
}

callCFunction()

The result is

create:2
ptr:0x000060000161e760
passRetained:3
takeRetainedValue:3
create:2
ptr:0x000060000161e760
passRetained:3
takeRetainedValue:3

passUnretained & takeUnretainedValue

Unmanaged.passUnretained(obj) static method creates an unmanaged reference to the object and does not change its retain account.

Conversely, takeRetainedValue() instance method of an Unmanaged instance will return a managed reference and does not change its retain count as well.

For example:

swift
import Foundation

class MyClass {
    var value: Int
    init(value: Int) {
        self.value = value
    }
}

func cFunction(_ obj: UnsafeMutableRawPointer) {
    let unmanaged = Unmanaged<MyClass>.fromOpaque(obj)
    let myObject = unmanaged.takeUnretainedValue()
    print("takeUnretainedValue:\(CFGetRetainCount(myObject))")
    // takeUnretainedValue() -> retainAccount does change
    // myObject -> retainAccount + 1
}

func callCFunction() {
    let myObject = MyClass(value: 42)
    print("create:\(CFGetRetainCount(myObject))")
    let ptr = Unmanaged.passUnretained(myObject).toOpaque()
    print("ptr:\(ptr)")
    print("passUnretained:\(CFGetRetainCount(myObject))")
    cFunction(ptr)
}

callCFunction()
import Foundation

class MyClass {
    var value: Int
    init(value: Int) {
        self.value = value
    }
}

func cFunction(_ obj: UnsafeMutableRawPointer) {
    let unmanaged = Unmanaged<MyClass>.fromOpaque(obj)
    let myObject = unmanaged.takeUnretainedValue()
    print("takeUnretainedValue:\(CFGetRetainCount(myObject))")
    // takeUnretainedValue() -> retainAccount does change
    // myObject -> retainAccount + 1
}

func callCFunction() {
    let myObject = MyClass(value: 42)
    print("create:\(CFGetRetainCount(myObject))")
    let ptr = Unmanaged.passUnretained(myObject).toOpaque()
    print("ptr:\(ptr)")
    print("passUnretained:\(CFGetRetainCount(myObject))")
    cFunction(ptr)
}

callCFunction()

The result is

create:2
ptr:0x00006000030bd760
passUnretained:2
takeUnretainedValue:3
create:2
ptr:0x00006000030bd760
passUnretained:2
takeUnretainedValue:3

toOpaque & fromOpaque

Converting between an unmanaged class reference and an opaque C pointer.

swift
func toOpaque() -> UnsafeMutableRawPointer
static func fromOpaque(_ value: UnsafeRawPointer) -> Unmanaged<Instance>
func toOpaque() -> UnsafeMutableRawPointer
static func fromOpaque(_ value: UnsafeRawPointer) -> Unmanaged<Instance>

Example code:

swift
let myObject = MyClass(value: 42)
let unmanaged1 = Unmanaged.passUnretained(myObject)
let ptr = unmanaged1.toOpaque()
print("ptr:\(ptr)")
let unmanaged2 = Unmanaged<MyClass>.fromOpaque(ptr)
let myObject = MyClass(value: 42)
let unmanaged1 = Unmanaged.passUnretained(myObject)
let ptr = unmanaged1.toOpaque()
print("ptr:\(ptr)")
let unmanaged2 = Unmanaged<MyClass>.fromOpaque(ptr)

References