I'm trying to understand why there exists both CF and NS objects, which seem to do the same thing and are interchangeable through toll-free bridging. If, say, CFArray and NSArray do the same thing, and I can cast between them freely, what's the point in both of them existing? Are there rules of thumb about when to use one over the other? Are the CF objects just legacy objects from old frameworks? Any insight into this would be greatly appreciated.
To answer your questions in order:
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.
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]) 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
NSDictionary classes don't let you do that - they always assume you are storing reference-counted objects.
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
CFStream to be very informative.