CFBag
Objective-C is a language caught between two worlds.
On one side, it follows the thoughtful, object-oriented philosophy of Smalltalk, which brings ideas like message sending and named parameters. On the other, are the inescapable vestiges of C, which brings it power and a dash of chaos.
It’s an identity crisis borne out through an ever-increasing prevalence of the @
symbol.
This is also seen in the relationship between the Foundation and Core Foundation, particularly with the toll-free bridged collection class clusters: NSArray
/ CFArray
, NSDictionary
/ CFDictionary
, NSSet
/ CFSet
. These collections can be passed back and forth between C functions and Objective-C methods without conversion. A leak in the abstraction, but a useful way to optimize the most critical parts of an application nonetheless.
However, toll-free bridging is the exception when it comes to collection classes in Foundation and Core Foundation:
Foundation | Core Foundation | Toll-Free Bridged |
---|---|---|
NSArray *
|
CFArray *
|
✓ |
NSCounted |
CFBag *
|
|
N/A | CFBinary |
|
N/A |
CFBit *
|
|
NSDictionary *
|
CFDictionary *
|
✓ |
NSIndex *
|
N/A | |
NSMap |
N/A | |
NSOrdered |
N/A | |
NSPointer |
N/A | |
NSPointer |
N/A | |
NSSet *
|
CFSet *
|
✓ |
* Indicates Mutable Counterpart |
Take a look at the second row, with NSCounted
and CFBag
. Notice that unlike the other Foundation / Core Foundation correspondence, these two are not toll-free bridged. No real explanation for this is provided in the documentation, aside from it being acknowledged in the NSCounted
documentation. My guess is that it has something to do with NSCounted
not having a mutable counterpart, and thus breaking the class cluster pattern seen in NSArray
, et al.
Bags, in the Abstract
In the pantheon of collection data types in computer science, bag doesn’t really have the same clout as lists, sets, associative arrays, trees, graphs, or priority queues.
In fact, it’s pretty obscure. You’ve probably never heard of it.
A bag, or multiset is a variant of a set, where members can appear more than once. A count is associated with each unique member of the collection, representing the number of times it has been added. Like with sets, order does not matter.
Its practical applications are… limited, but you’ll know one when it comes up. Tallying votes in a general election? Simulating homework problems an intro probability class? Implementing a game of Yahtzee? Bag is your new bicycle!
CFMutable Bag
Working with As an implementation of the bag data type, CFBag
and its mutable counterpart, CFMutable
, are pretty slick.
Although it lacks the object-oriented convenience of NSCounted
, it makes up for it with a number of ways to customize its behavior. When CFBag
is created, it can be initialized with a number of callbacks, defined by the CFBag
struct, which specify the way values are inserted, removed, and compared:
struct CFBag Call Backs {
CFIndex version;
CFBag Retain Call Back retain;
CFBag Release Call Back release;
CFBag Copy Description Call Back copy Description;
CFBag Equal Call Back equal;
CFBag Hash Call Back hash;
};
typedef struct CFBag Call Backs CFBag Call Backs;
-
retain
: callback used to retain values as they’re added to the collection -
release
: callback used to release values as they’re removed from the collection -
copy
: callback used to create a string description of each value in the collectionDescription -
equal
: callback used to compare values in the collection for equality -
hash
: callback used to compute hash codes for values in the collection
For example, if you were implementing a vote tallying application, you could specify a normalizing function for retain
to ensure that votes for mixed-case or misspelled names went to the right candidate, or ensure that the “correct” candidate is shown to be the winner when all the votes are in, with equal
callback.
CFMutable
also has CFBag
, which has the ability to transform values over the collection, like if you wanted to smooth out vote counts, or something like that.
So in closing, if you need to rig an election, CFBag
is your best bet.
But seriously, CFBag
, useful in its own right, serves as a reminder of the hidden gems to be found within the standard frameworks and libraries–indeed what is at the very heart of being an NSHipster.
Also, CFBinary
? NSPointer
? NSMap
? Surely, you’ll be seeing more of these in future editions.