Benedict's Soapbox

EMKTypedArray EMKMutableTypedArray: Storing primitives and struct in Objective-C

Cocoa and Core Foundation have a wide range of collection classes for managing objects. On the Cocoa side there’s NSArray, NSDictionary, NSSet, NSCountedSet. These classes are based on the opaque Core Foundation structures CFArray, CFDictionary and CFSet, CFBag, CFBinaryHeap and CFTree. The Cocoa classes are fine 90% of the time, but if you need a more flexibility then Core Foundation can accommodate.

All of the afore mentioned classes are designed to work with objects. Cocoa supplies NSHashTable and NSPointerArray for working with pointers and NSIndexSet for working integers. There are no collection classes for other C primitives or structs. This presents a problem when you want to store an array of non-objects such as floats or ints.

One solution is to wrap the primitive values in an NSValue (or one of its subclasses) and insert that into an NSArray. This isn’t a very elegant solution (it involves lots of boiler plate code to get the values in and out of the array) and it consumes a great deal of memory. Another solution is use C++ vectors. I can’t comment on this solution as my C++ knowledge is close to non-existent. A third solution is to use a C array. C arrays are cheap with regards to memory, but the code a bit messier.

To solve this problem in an Objective-C friendly manner I’ve create EMKTypedArray and EMKMutableTypedArray. The basic approach is the C solution outlined above. Here’s a usage example:

//Create an array  
CGPoint points[2] = {CGPointMake(10,10), CGPointMake(20, 20)};  
EMKMutableTypedArray *pointArray = [EMKMutableTypedArray typedArrayWithTypeSizeof:sizeof(CGPoint) bytes:points count:2 defaultValue:&CGPointZero];

CGPoint value;  
uint i, pointCount;  
for (i = 0, pointCount = [pointArray count]; i < pointCount; i++)  
{  
    [pointArray getValue:&value atIndex:i];  
    NSLog(@"%i: %f, %f", i, value.x, value.y);  
}  
//0: 10, 10  
//1: 20, 20

//add a value  
CGPoint point = (CGPoint){.x = 40, .y = 40};  
[pointArray setValue:&point atIndex:3];

for (i = 0, pointCount = [pointArray count]; i < pointCount; i++)  
{  
    [pointArray getValue:&value atIndex:i];  
    NSLog(@"%i: %f, %f", i, value.x, value.y);  
}  
//0: 10, 10  
//1: 20, 20  
//2: 0, 0  
//3: 40, 40

//shrink the array  
[pointArray trimToLength:2];

for (i = 0, pointCount = [pointArray count]; i < pointCount; i++)  
{  
    [pointArray getValue:&value atIndex:i];  
    NSLog(@"%i: %f, %f", i, value.x, value.y);  
}  
//0: 10, 10  
//1: 20, 20

Download

EMKTypedArray and EMKMutableTypedArray are part of my GitHub project, EMKPantry.