I have a 2D array of pointers to Objective-C instances to keep track of game objects on a map grid. Now I am transitioning my code to ARC, and Xcode pointed the error. I knew pointers to objects aren't allowed as struct members, but this one caught me (almost) off guard.
我有一个指向Objective-C实例的2D数组,以跟踪地图网格上的游戏对象。现在我将我的代码转换为ARC,Xcode指出错误。我知道指向对象的指针不允许作为结构成员,但这个让我(差点)措手不及。
I understand the rationale behind the ARC constrains, but:
我理解ARC约束背后的基本原理,但是:
-
I can't afford the overhead of objective-C arrays when looking up objects in the grid, and
在网格中查找对象时,我无法负担Objective-C数组的开销
-
The objects themselves are already owned by an
NSArray
ivar defined in the same class that has the C-style grid as an ivar; the c-style array is only a conveniently structured shortcut. Futhermore, when objects are removed from the owningNSArray
, I set the corresponding grid slot toNULL
.对象本身已经由同一类中定义的NSArray ivar拥有,该类具有作为ivar的C风格网格; c风格的数组只是一个方便的结构化快捷方式。此外,当从拥有的NSArray中删除对象时,我将相应的网格槽设置为NULL。
That is, the 2D array (grid) is just a collection of fast (but dumb) pointers to objects safely retained somewhere else (the NSArray
ivar).
也就是说,2D数组(网格)只是快速(但是愚蠢)指向安全保留在其他地方的对象(NSArray ivar)的集合。
Is there a way to get away with this using casts? For example, define and alloc my grid as:
有没有办法摆脱使用演员阵容?例如,将我的网格定义并分配为:
void*** _grid;
instead of
代替
MyMapObjectClass*** _grid
and use (appropriately bridged) casts between void*
<-> MyMapObjectClass*
when setting or getting the pointers in each slot?
在每个插槽中设置或获取指针时,在void * < - > MyMapObjectClass *之间使用(适当桥接)强制转换?
EDIT: So here is how I solved it
编辑:所以这就是我如何解决它
I changed the ivar declaration as described above. In addition, when setting an entry of my look-up grid, I did this:
我如上所述更改了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;
When accessing the object at (x,y), I do the opposite:
在(x,y)访问对象时,我做了相反的事情:
MyMapObjectClass* object = (__bridge MyMapObjectClass*) _grid[x][y];
[object performSomeMethod];
// etc...
When removing the object from the map, I do this:
从地图中删除对象时,我这样做:
MyMapObjectClass* object = (__bridge MyMapObjectClass*) _grid[x][y];
[_objectArray removeObject:object];
_grid[x][y] = NULL;
Map objects are created once at the beginning of the game, and removed according to game progress. If I need to replace a map object for another, I would do this:
地图对象在游戏开始时创建一次,并根据游戏进度删除。如果我需要替换另一个地图对象,我会这样做:
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;
1 个解决方案
#1
2
Circumventing ARC using casts is generally a bad idea. The better way would be to disable ARC for your map.m (or break out just the lookup part into a separate class).Then do manual memory management inside it with retain
/ release
and the C structures you like, as long as you do it correctly it will work fine and you will be able to call it from other classes, avoiding the overhead of nested NSArrays
etc..
使用演员阵容绕过ARC是一个坏主意。更好的方法是为map.m禁用ARC(或者将查找部分分解为单独的类)。然后使用retain / release和你喜欢的C结构在其中进行手动内存管理,只要你做它正确它将正常工作,你将能够从其他类调用它,避免嵌套NSArrays等的开销。
#1
2
Circumventing ARC using casts is generally a bad idea. The better way would be to disable ARC for your map.m (or break out just the lookup part into a separate class).Then do manual memory management inside it with retain
/ release
and the C structures you like, as long as you do it correctly it will work fine and you will be able to call it from other classes, avoiding the overhead of nested NSArrays
etc..
使用演员阵容绕过ARC是一个坏主意。更好的方法是为map.m禁用ARC(或者将查找部分分解为单独的类)。然后使用retain / release和你喜欢的C结构在其中进行手动内存管理,只要你做它正确它将正常工作,你将能够从其他类调用它,避免嵌套NSArrays等的开销。