Browse Questions
Answer:
Prevent Core Foundation memory leaks in Swift by correctly balancing Unmanaged<T>.passRetained() with takeRetainedValue() and pairing every retained C-level allocation with CFRelease.
Core Foundation (CF) types use C-style manual memory management. ARC does not automatically track CF reference counts unless bridging is handled explicitly.
passRetained: Increments the retain count. Use when passing a Swift class instance to a C API that expects to own a reference.passUnretained: Does NOT increment retain count. Use when the C API borrows the object temporarily without taking ownership.takeRetainedValue: Consumes an existing retain count and transfers ownership to ARC (ARC will balance it with a release later).takeUnretainedValue: Borrows the value without decrementing its CF retain count.
Code Example:
class CustomDataHandler {
let name: String = "Handler"
}
// 1. Passing Swift object into C callback context (retained)
let handler = CustomDataHandler()
let unmanagedPointer = Unmanaged.passRetained(handler).toOpaque()
// ... C API executes callback with void* context ...
// 2. Consuming object in C callback and transferring ownership back to ARC
let restoredHandler = Unmanaged<CustomDataHandler>.fromOpaque(unmanagedPointer).takeRetainedValue()
print("Restored: \(restoredHandler.name)") // ARC handles cleanup when restoredHandler leaves scope
// 3. Direct Core Foundation types
let cfArray: CFArray = CFArrayCreate(nil, nil, 0, nil)
// When bridging with __bridge_transfer in Swift:
let swiftArray = cfArray as [AnyObject] // ARC assumes ownership and releases CFArray
Key Points:
- Calling
takeRetainedValue()on an un-retained pointer causes a crash (over-release) - Calling
takeUnretainedValue()on a retained pointer causes a permanent memory leak (under-release)