- Optionals 101
- Unwrapping Optionals
- Optional Chaining
- Optional Mapping
- Unmanaged Wrappers
- Wrap-up
Unmanaged Wrappers
In rare cases (which are growing rarer by the day), a Core Foundation function may return a C pointer or an object reference embedded in an Unmanaged wrapper. You encounter these in the older, dustier, and stranger parts of Cocoa, where grues still lurk in shadows. Keychain Services is a notorious offender in this regard. You must transfer Unmanaged references into the normal memory management system before working with them.
An Unmanaged wrapper, like an Optional wrapper, provides a layer of safety between your code and a potentially nasty crash. The Unmanaged<T> type stores a pointer whose memory is not controlled by the Swift runtime system. Before using this data, you take responsibility for how this memory should stay alive.
In Cocoa, this works very much like bridging in Objective-C. Unwrap any object with an existing +1 retain count using takeRetainedValue(). This applies to any item built with Create or Copy in its name. Use takeUnretainedValue() for +0 returns.
If you have an Objective-C framework or are developing one that you would like people to use in their Swift application—and if there are methods or functions in your Objective-C framework that return Core Foundation objects—decorate your methods or function names with CF_RETURNS_RETAINED or CF_RETURNS_NOT_RETAINED. If you don’t decorate your methods or functions, Core Foundation objects are returned as unmanaged.
In Swift 2, CF-IMPLICIT-BRIDGING-ENABLED and CF-IMPLICIT-BRIDGING-DISABLED automatically bridge based on Core Foundation naming conventions. So if you audit your APIs and ensure that they follow get/copy/create conventions, you can avoid specific method decoration.
For example, UTTypeCopyPreferredTagWithClass returns a +1 CFString instance. Assign this result with takeRetainedValue(), making sure to test for failed calls. Unwrapping nil causes nasty crashes that even blessed potions of restore life will not fix. Recipe 3-4 demonstrates how to use unmanaged wrappers by returning a preferred file extension for a given universal type indicator.
Recipe 3-4 Conditional Binding from Unmanaged Wrappers
import MobileCoreServices Import Foundation enum Error: ErrorType {case NoMatchingExtension} public func preferredFileExtensionForUTI(uti: String) throws -> String { if let result = UTTypeCopyPreferredTagWithClass( uti, kUTTagClassFilenameExtension) { return result.takeRetainedValue() as String } throw Error.NoMatchingExtension }
This recipe uses conditional binding. The UTTypeCopyPreferredTagWithClass() function returns Unmanaged<CFString>?, which is an optional instance. If the call fails and returns nil, the function throws an error. Test the recipe by passing it a few common UTIs, such as public.jpeg and public.aiff-audio:
let shouldBeJPEG = try PreferredFileExtensionForUTI("public.jpeg") let shouldBeAIFF = try PreferredFileExtensionForUTI("public.aiff-audio")
Use takeUnretainedValue() to unwrap any object built by a Core Foundation function with Get in its name (for example, CFAllocatorGetDefault()) and constants passed as unmanaged objects (for example, kLSSharedFileListSessionLoginItems). These items are not automatically retained for you. Unlike with takeRetainedValue(), calling takeUnretainedValue() won’t consume a retain upon unwrapping.
These functions follow the patterns established in Apple’s Memory Management Programming Guide for Core Foundation, where you can read more about the “create rule,” the “get rule,” and other details about memory ownership policies. Search the web for the latest update of this document.