What's the best way to put a c-struct in an NSArray?
NSValue doesn't only support CoreGraphics structures – you can use it for your own too. I would recommend doing so, as the class is probably lighter weight than NSData
for simple data structures.
Simply use an expression like the following:
[NSValue valueWithBytes:&p objCType:@encode(Megapoint)];
And to get the value back out:
Megapoint p;
[value getValue:&p];
I would suggest you stick to the NSValue
route, but if you really do wish to store plain 'ol struct
datatypes in your NSArray (and other collection objects in Cocoa), you can do so -- albeit indirectly, using Core Foundation and toll-free bridging.
CFArrayRef
(and its mutable counterpart, CFMutableArrayRef
) afford the developer more flexibility when creating an array object. See the fourth argument of the designated initialiser:
CFArrayRef CFArrayCreate (
CFAllocatorRef allocator,
const void **values,
CFIndex numValues,
const CFArrayCallBacks *callBacks
);
This allows you to request that the CFArrayRef
object use Core Foundation's memory management routines, none at all or even your own memory management routines.
Obligatory example:
// One would pass &kCFTypeArrayCallBacks (in lieu of NULL) if using CF types.
CFMutableArrayRef arrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
NSMutableArray *array = (NSMutableArray *)arrayRef;
struct {int member;} myStruct = {.member = 42};
// Casting to "id" to avoid compiler warning
[array addObject:(id)&myStruct];
// Hurray!
struct {int member;} *mySameStruct = [array objectAtIndex:0];
The above example completely ignores the issues with respect to memory management. The structure myStruct
is created on the stack and hence is destroyed when the function ends -- the array will contain a pointer to an object that is no longer there. You can work around this by using your own memory management routines -- hence why the option is provided to you -- but then you have to do the hard work of reference counting, allocating memory, deallocating it and so on.
I would not recommend this solution, but will keep it here in case it is of interest to anyone else. :-)
Using your structure as allocated on the heap (in lieu of the stack) is demonstrated here:
typedef struct {
float w, x, y, z;
} Megapoint;
// One would pass &kCFTypeArrayCallBacks (in lieu of NULL) if using CF types.
CFMutableArrayRef arrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
NSMutableArray *array = (NSMutableArray *)arrayRef;
Megapoint *myPoint = malloc(sizeof(Megapoint);
myPoint->w = 42.0f;
// set ivars as desired..
// Casting to "id" to avoid compiler warning
[array addObject:(id)myPoint];
// Hurray!
Megapoint *mySamePoint = [array objectAtIndex:0];
A similar method to add c struct is to store the pointer and to de-reference the pointer as so;
typedef struct BSTNode
{
int data;
struct BSTNode *leftNode;
struct BSTNode *rightNode;
}BSTNode;
BSTNode *rootNode;
//declaring a NSMutableArray
@property(nonatomic)NSMutableArray *queues;
//storing the pointer in the array
[self.queues addObject:[NSValue value:&rootNode withObjCType:@encode(BSTNode*)]];
//getting the value
BSTNode *frontNode =[[self.queues objectAtIndex:0] pointerValue];