Welcome to Core Foundation world! In Swift, the memory management for Core Foundation (as well as a series of other Core frameworks) is greatly simplified. It allows us to work better and easier with those Core Foundation (CF for short later) APIs.
First take a look at toll-free bridging in Cocoa. A lot of
NS classes have their corresponding CF types. In fact, the
NS prefixed classes are only a higher level encapsulation for the CF types. For example,
NSURL has a similar memory structure with
NSString is an abstract for
In Objective-C, ARC will only take the responsibility of reference counting for
NSObject and its subclass. The memory of CF objects is not managed by ARC mechanism. When we convert objects from
CF or vice versa, we need to tell the compiler how does the memory ownership changes. For those situation that the memory owner does not change, we should add
__bridge to describe it. The code below transforms an
NSURL object to
CFURLRef without transferring the memory ownership:
NSURL *fileURL = [NSURL URLWithString:@"SomeURL"]; SystemSoundID theSoundID; OSStatus error = AudioServicesCreateSystemSoundID( (__bridge CFURLRef)fileURL, &theSoundID);
fileURL object will be released properly when out of scope.
In Swift, thing gets simpler. We could rewrite the code above like this, which is much easier and cleaner:
let fileURL = NSURL(string: "SomeURL") var theSoundID: SystemSoundID = 0 AudioServicesCreateSystemSoundID(fileURL, &theSoundID)
You may already find the CF type of URL is
CFURL here, while in Objective-C it is
CFURLRef. In Swift,
CFURL is just a typealias of
CFURL. Besides of URL, other CF types also follow this. The main purpose is reducing the confusing of the API name. In Swift, these CF types behave more like types under management of ARC. It will be clearer to remove the
Ref from the type name.
In Objective-C, ARC cannot handle the creation and releasing of CF types. There is a naming convention in CF: If
Retain exists in a CF API, after using the instance, we need to use
CFRelease to release the object.
But in Swift, this rule is not needed anymore. Developers asked, since we already have the name convention, why not just do the release for me? Yes! In Swift we never need to call the CFRelease method (actually you will get an error if you write it). In other words, CF types now are under control of ARC. The under hood is similar to invoking of
NSObject, the compiler will insert
CF_RETURNS_NOT_RETAINED in proper position for us based on the code.
However, there is an exception. Swift cannot handle your own CF API. That means if you write your own method or use some third party code which returns an instance of CF type, you have to manage the memory yourself. There is no mechanism to force those codes to follow the Cocoa name convention, so it is not possible to auto management. If you didn't use the memory annotation in the methods, you will get a
Unmanaged<T> instead of the CF type.
To manage the memory manually, we would use the
takeRetainedValue method of the
Unmanaged object to get out the corresponding CF object, and deal with its reference count at the same time.
takeUnretainedValue will keep the reference count unchanged. When you know it is not your responsibility to release the object, you should use this to retrieve the CF object. Otherwise, if you hold that object, and must release it later, you should use
takeRetainedValue to increase the reference count. After used, you should also release the original
Unmanaged object manually. There are still
autorelease methods for us to use. Generally speaking, when you use it, you might write like this:
// CFGetSomething() -> Unmanaged<Something> // CFCreateSomething() -> Unmanaged<Something> // There is no annotation. And a new instance is created in the "Create" API. let unmanaged = CFGetSomething() let something = unmanaged.takeUnretainedValue() // After we called takeUnretainedValue, something is an instance of Something let unmanaged = CFCreateSomething() let something = unmanaged.takeRetainedValue() // Use something // Since the value of unmanaged is retained, we should release it now unmanaged.release()
Remember, you might rarely use this, unless you are working with a lot of customized CF API. If your daily work is app development, it seems OK even you have no idea about memory management customized CF APIs.