10

我有一个指向 Objective-C 实例的 2D 指针数组,以跟踪地图网格上的游戏对象。现在我正在将我的代码转换为 ARC,Xcode 指出了错误。我知道不允许将指向对象的指针作为结构成员,但是这个让我(几乎)措手不及。

我理解 ARC 约束背后的基本原理,但是:

  1. 在网格中查找对象时,我无法承受 Objective-C 数组的开销,并且

  2. 对象本身已经由NSArray定义在同一类中的 ivar 拥有,该类将 C 样式网格作为 ivar;c 风格的数组只是一种结构方便的快捷方式。此外,当从拥有的对象中删除对象时NSArray,我将相应的网格槽设置为NULL

也就是说,二维数组(网格)只是快速(但愚蠢)指针的集合,指向安全地保留在其他地方(NSArrayivar)的对象。

有没有办法使用演员来摆脱这种情况?例如,将我的网格定义和分配为:

void*** _grid;

代替

MyMapObjectClass*** _grid

并在设置或获取每个插槽中的指针时在void*<->之间使用(适当桥接)强制转换?MyMapObjectClass*

编辑:所以这就是我解决它的方法

我如上所述更改了 ivar 声明。此外,在设置我的查找网格的条目时,我这样做了:

// (Done **Only Once** at map initialization) 
// _objectArray is an instance of NSMutableArray

MyMapObjectClass* mapObject = [[MyMapObjectClass alloc] init];

// ...configure map object, etc...

// Add to Obj-C array:
[_objectArray addObject:mapObject];

// Add pointer to 2D C array:
_grid[i][j] = (__bridge void*)mapObject;

当访问 (x,y) 处的对象时,我会做相反的事情:

MyMapObjectClass* object = (__bridge MyMapObjectClass*) _grid[x][y];

[object performSomeMethod];

// etc...

从地图中删除对象时,我这样做:

MyMapObjectClass* object = (__bridge MyMapObjectClass*) _grid[x][y];

[_objectArray removeObject:object];

_grid[x][y] = NULL;

地图对象在游戏开始时创建一次,并根据游戏进度移除。如果我需要替换另一个地图对象,我会这样做:

MyMapObjectClass* oldObject = (__bridge MyMapObjectClass*) _grid[x][y];
// (should mark as weak?)

[_objectArray removeObject:oldObject];    
_grid[x][y] = NULL;

MyMapObjectClass* newObject = [[MyMapObjectClass alloc] init];

[_objectArray addObject:newObject];

_grid[x][y] = (__bridge void*)newObject;
4

1 回答 1

2

使用强制转换来规避 ARC 通常是个坏主意。更好的方法是为您的 map.m禁用 ARCretain (或将查找部分分解为单独的类)。然后使用/release和您喜欢的 C 结构在其中进行手动内存管理,只要您正确执行它会正常工作,您将能够从其他类调用它,避免嵌套NSArrays等的开销。

于 2012-06-22T12:21:50.383 回答