CF objects vs NS objects

Solution 1:

To answer your questions in order:

  1. What's the point of them both existing? There are a few reasons.

    If you want to provide a C API, like the Carbon API, and you need things like arrays and dictionaries of referenced-counted objects, you want a library like Core Foundation (which provides CFArray), and of course it needs to have a C API.

    If you want to write libraries for third-parties to use on Windows (for example), you need to provide a C API.

    If you want to write a low-level library, say for interfacing with your operating system's kernel, and you don't want the overhead of Objective-C messaging, you need a C API.

    So those are good reasons for having Core Foundation, a pure C library.

    But if you want to provide a higher-level, more pleasant API in Objective-C, you want Objective-C objects that represent arrays, dictionaries, reference-counted objects, and so on. So you need Foundation, which is an Objective-C library.

  2. When should you use one or the other? Generally, you should use the Objective-C classes (e.g. NSArray) whenever you can, because the Objective-C interface is more pleasant to use: myArray.count (or [myArray count]) is easier to read and write than CFArrayGetCount(myArray). You should use the Core Foundation API only when you really need to: when you're on a platform that doesn't have Objective-C, or when you need features that the Core Foundation API provides but the Objective-C objects lack. For example, you can specify callbacks when creating a CFArray or a CFDictionary that let you store non-reference-counted objects. The NSArray and NSDictionary classes don't let you do that - they always assume you are storing reference-counted objects.

  3. Are the CF objects just legacy objects? Not at all. In fact, Nextstep existed for years with just the Objective-C Foundation library and no (public) Core Foundation library. When Apple needed to support both the Carbon API and the Cocoa API on top of the same lower-level operating system facilities, they created (or made public) Core Foundation to support both.

Incidentally, some of Core Foundation is open source. You can find the open source part of it for Mac OS X 10.10.5 here: https://opensource.apple.com/source/CF/CF-1153.18/. I have found the source code of CFRunLoop and CFStream to be very informative.

Solution 2:

Core Foundation is a C API to a variety of common data structures. Most of these data structures have equivalents in Cocoa, but not all of them. Most of the ones that are equivalent are toll free bridged, allowing them to be used interchangeably, but not all of them either.

Toll free bridging is a very clever implementation trick. If you want the underlying details, see the ridiculous_fish post that @Matt Wilding points out. It's the most authoritative on the subject (and a major influence on iOS:PTL chapter 19 which also explains how it all works). But it doesn't really matter for most purposes. As Matt notes, you can generally pretend that an NSArray is the same as a CFArrayRef. This isn't really true in many cases, but it's sometimes true, and close enough most of the time. It's the same as saying that @"stuff" is the same as an NSString containing stuff. It's mostly true, but not exactly.

When OS 9 moved to OS X, it was very convenient to provide C access to Objective-C-like data structures. Many low-level frameworks today expose C APIs for performance reasons. You shouldn't think of CF as "legacy" or "internal." You should think of it as low-level and you should only use it when you need the power it provides, or are dealing with a low-level framework that requires it.

CF objects are often more flexible than their NS counterparts. For example, CFDictionaryRef can contain non-object keys and values, while NSDictionary can't. (Of course they're toll-free bridged, so you can create a non-retaining CFDictionaryRef and then treat it as an NSDictionary. Tricky that....)

As Apple releases new frameworks, you'll notice that they often expose C APIs first, and then later add Objective-C APIs. This is a reason that it's a good idea to learn Core Foundation, even if you don't use it every day. But when possible, you generally should be using ObjC.

Solution 3:

There's some history to this question. Core Foundation is the brains of the operation. It's written mostly in C. It was created with Apple's acquisition of NEXT and their APIs and owes a lot to them. The NS* classes are often just Objective C abstract interfaces built on top of the CF* types. So, when you ask why both CFArray and NSArray exist, the answer is that they actually don't. NSArrays are CFArrays, NSStrings are CFStrings, etc. That's why toll-free-bridging is possible.

For more interesting and detailed reading, I would refer you to this blog post.