将c-struct放入NSArray的最佳方法是什么?

Fat*_*tie 84 iphone cocoa struct objective-c nsarray

存储c结构的常用方法是NSArray什么?优点,缺点,内存处理?

值得注意的是,有什么之间的区别valueWithBytesvalueWithPointer -由Justin和鲶鱼下面提出.

这是 Apple valueWithBytes:objCType:对未来读者讨论的链接 ......

对于一些横向思考和更多关注性能,Evgen提出了STL::vectorC++中使用的问题.

(这引发了一个有趣的问题:是否有一个快速的c库,不是STL::vector很轻,但更轻,允许最小的"整理数组处理"......?)

那么原来的问题......

例如:

typedef struct _Megapoint {
    float   w,x,y,z;
} Megapoint;
Run Code Online (Sandbox Code Playgroud)

那么:在一个NSArray成语中存储一个人自己的结构的正常,最好,惯用的方式是什么?你如何处理那个成语中的记忆?

请注意,我特意寻找存储结构的通常习惯用法.当然,人们可以通过创建一个新的小班来避免这个问题.但是,我想知道实际将结构放入数组的常用习惯,谢谢.

顺便说一句,这可能是NSData的方法吗?不是最好的......

Megapoint p;
NSArray *a = [NSArray arrayWithObjects:
    [NSData dataWithBytes:&p length:sizeof(Megapoint)],
    [NSData dataWithBytes:&p length:sizeof(Megapoint)],
    [NSData dataWithBytes:&p length:sizeof(Megapoint)],
        nil];
Run Code Online (Sandbox Code Playgroud)

BTW作为参考点,感谢Jarret Hardie,以下是如何存储CGPoints和类似的NSArray:

NSArray *points = [NSArray arrayWithObjects:
        [NSValue valueWithCGPoint:CGPointMake(6.9, 6.9)],
        [NSValue valueWithCGPoint:CGPointMake(6.9, 6.9)],
        nil];
Run Code Online (Sandbox Code Playgroud)

(请参阅如何以简单的方式将CGPoint对象添加到NSArray?)

Jus*_*ers 154

NSValue不仅支持CoreGraphics结构 - 您也可以使用它.我建议这样做,因为类可能比NSData简单的数据结构更轻.

只需使用如下表达式:

[NSValue valueWithBytes:&p objCType:@encode(Megapoint)];
Run Code Online (Sandbox Code Playgroud)

并获得价值:

Megapoint p;
[value getValue:&p];
Run Code Online (Sandbox Code Playgroud)

  • @Joe Blow @Catfish_Man它实际上复制了结构`p`,而不是指向它的指针.`@ encode`指令提供了有关结构有多大的所有必要信息.当你释放`NSValue`(或数组的时候),它的结构副本就被破坏了.如果你在此期间使用过`getValue:`,那你就没事了.请参阅"数字和值编程主题"的"使用值"部分:http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/NumbersandValues/Articles/Values.html#//apple_ref/doc/ UID/20000174-BAJJHDEG (4认同)

Sed*_*ien 7

我建议你坚持这NSValue条路线,但是如果你真的希望struct在你的NSArray(以及Cocoa中的其他集合对象)中存储普通的'ol 数据类型' ,你可以这样做 - 虽然是间接的,使用Core Foundation和免费桥接.

CFArrayRef(及其可变对应物CFMutableArrayRef)在创建数组对象时为开发人员提供了更大的灵活性.请参阅指定初始化程序的第四个参数:

CFArrayRef CFArrayCreate (
    CFAllocatorRef allocator,
    const void **values,
    CFIndex numValues,
    const CFArrayCallBacks *callBacks
);
Run Code Online (Sandbox Code Playgroud)

这允许您请求CFArrayRef对象使用Core Foundation的内存管理例程,根本不使用甚至是您自己的内存管理例程.

必要的例子:

// 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];
Run Code Online (Sandbox Code Playgroud)

上面的例子完全忽略了内存管理方面的问题.结构myStruct在堆栈上创建,因此在函数结束时被销毁 - 数组将包含指向不再存在的对象的指针.您可以通过使用自己的内存管理例程来解决这个问题 - 因此为什么提供选项 - 但是您必须进行引用计数,分配内存,解除分配等等的艰苦工作.

我不推荐这个解决方案,但会保留在这里以防其他人感兴趣.:-)


使用在堆上分配的结构(代替堆栈)在此处演示:

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];
Run Code Online (Sandbox Code Playgroud)