EXC_BAD_ACCESS 将 NSValue 解码为 b2fixture 时
EXC_BAD_ACCESS when decoding NSValue into b2fixture
这个问题已经有一段时间了。我正在使用 box2D 并将 b2fixture 编码为 NSValue。当我使用
解码时出现问题
[value getValue:&fixture];
这段代码在 2012 年在我的旧 mac 上运行良好,但似乎在过去 4 年的某处矩阵中发生了一些事情!
编码和解码的相关代码如下:
vertGrid = [[NSMutableArray alloc] initWithCapacity:(NSUInteger) xUnits];
for (int x = 0; x <= xUnits; x++) {
b2Fixture *fixture = ... (not relevant)
NSValue *wrappedValue = [NSValue value:&fixture withObjCType:@encode(struct b2Fixture)];
[vertGrid addObject:wrappedValue];
}
//test I can unwrap the vertGrid
for (NSValue *value in vertGrid) {
b2Fixture *fixture;
[value getValue:&fixture];
NSLog(@"yo yo yo");
}
如果成功了,那纯属偶然。您没有包装内容,而是不小心复制了指针。内存管理和内存对齐的变化现在可能 "break"(32 位与 64 位?)。
无论如何,您的包装和展开都是错误的,因为它们都有一个额外的(不正确的)间接寻址。让我们从包装价值开始。您的代码是:
b2Fixture *fixture = ... (not relevant)
NSValue *wrappedValue = [NSValue value:&fixture withObjCType:@encode(struct b2Fixture)];
-[NSValue value:withObjCType:]
的文档提供了必要的信息:
value
: A pointer to data to be stored in the new value object.
由于您希望存储数据,因此您需要传递 struct b2Fixture *
,因为该方法随后将从该内存位置读取数据,但您传递的是 struct b2Fixture **
。因此将复制错误的数据(指针而不是数据)。
这是关于此方法实际工作原理的另一个提示:
This method has the same effect as valueWithBytes:objCType:
and may be deprecated in a future release. You should use valueWithBytes:objCType:
instead.
换句话说:该方法复制内容,而不是指向内容的指针。方法名称并不清楚,这就是为什么使用 valueWithBytes:objCType:
是更好的选择。
因此您对值进行包装的调用必须是:
NSValue *wrappedValue = [NSValue value:fixture withObjCType:@encode(struct b2Fixture)];
(注意缺少的&
)。
接下来,展开。你有:
b2Fixture *fixture;
[value getValue:&fixture];
再次,让我们看一下 documentation of -[NSValue getValue:]
,它说:
buffer
: A buffer into which to copy the value. The buffer must be large enough to hold the value
这意味着您需要分配存储空间。您在这里有两个选择:在库存上或在堆上分配。
// Allocate on the stack:
b2Fixture fixture;
[value getValue:&fixture];
// Allocate on the heap:
b2Fixture *fixture = malloc(sizeof(b2Fixture));
[value getValue:fixture]; // No "&"!
...
free(fixture);
评论后更新:
由于您似乎在尝试包装 C++ 对象,因此您需要采取不同的方式。我认为有两种方法可以解决这个问题:
- 增强对象,使其提供二进制表示形式并将其序列化。添加一个可以反序列化二进制表示的构造函数。
- 使用
+[NSValue valueWithPointer:]
and -[NSValue pointerValue]
。这假定对象存在于堆上,并且会使内存管理更加复杂。
这个问题已经有一段时间了。我正在使用 box2D 并将 b2fixture 编码为 NSValue。当我使用
解码时出现问题[value getValue:&fixture];
这段代码在 2012 年在我的旧 mac 上运行良好,但似乎在过去 4 年的某处矩阵中发生了一些事情!
编码和解码的相关代码如下:
vertGrid = [[NSMutableArray alloc] initWithCapacity:(NSUInteger) xUnits];
for (int x = 0; x <= xUnits; x++) {
b2Fixture *fixture = ... (not relevant)
NSValue *wrappedValue = [NSValue value:&fixture withObjCType:@encode(struct b2Fixture)];
[vertGrid addObject:wrappedValue];
}
//test I can unwrap the vertGrid
for (NSValue *value in vertGrid) {
b2Fixture *fixture;
[value getValue:&fixture];
NSLog(@"yo yo yo");
}
如果成功了,那纯属偶然。您没有包装内容,而是不小心复制了指针。内存管理和内存对齐的变化现在可能 "break"(32 位与 64 位?)。
无论如何,您的包装和展开都是错误的,因为它们都有一个额外的(不正确的)间接寻址。让我们从包装价值开始。您的代码是:
b2Fixture *fixture = ... (not relevant)
NSValue *wrappedValue = [NSValue value:&fixture withObjCType:@encode(struct b2Fixture)];
-[NSValue value:withObjCType:]
的文档提供了必要的信息:
value
: A pointer to data to be stored in the new value object.
由于您希望存储数据,因此您需要传递 struct b2Fixture *
,因为该方法随后将从该内存位置读取数据,但您传递的是 struct b2Fixture **
。因此将复制错误的数据(指针而不是数据)。
这是关于此方法实际工作原理的另一个提示:
This method has the same effect as
valueWithBytes:objCType:
and may be deprecated in a future release. You should usevalueWithBytes:objCType:
instead.
换句话说:该方法复制内容,而不是指向内容的指针。方法名称并不清楚,这就是为什么使用 valueWithBytes:objCType:
是更好的选择。
因此您对值进行包装的调用必须是:
NSValue *wrappedValue = [NSValue value:fixture withObjCType:@encode(struct b2Fixture)];
(注意缺少的&
)。
接下来,展开。你有:
b2Fixture *fixture;
[value getValue:&fixture];
再次,让我们看一下 documentation of -[NSValue getValue:]
,它说:
buffer
: A buffer into which to copy the value. The buffer must be large enough to hold the value
这意味着您需要分配存储空间。您在这里有两个选择:在库存上或在堆上分配。
// Allocate on the stack:
b2Fixture fixture;
[value getValue:&fixture];
// Allocate on the heap:
b2Fixture *fixture = malloc(sizeof(b2Fixture));
[value getValue:fixture]; // No "&"!
...
free(fixture);
评论后更新:
由于您似乎在尝试包装 C++ 对象,因此您需要采取不同的方式。我认为有两种方法可以解决这个问题:
- 增强对象,使其提供二进制表示形式并将其序列化。添加一个可以反序列化二进制表示的构造函数。
- 使用
+[NSValue valueWithPointer:]
and-[NSValue pointerValue]
。这假定对象存在于堆上,并且会使内存管理更加复杂。