У меня есть двумерный массив указателей на экземпляры Objective-C, чтобы отслеживать игровые объекты на сетке карты. Теперь я перевожу свой код на ARC, и Xcode указал на ошибку. Я знал, что указатели на объекты не разрешены в качестве членов структуры, но это застало меня (почти) врасплох.
Я понимаю причину ограничений ARC, но:
Я не могу позволить себе накладные расходы на массивы Objective-C при поиске объектов в сетке, и
Сами объекты уже принадлежат NSArray
ivar, определенный в том же классе, который имеет сетку в стиле C в качестве ivar; массив c-style — это всего лишь удобно структурированный ярлык. Более того, когда объекты удаляются из владеющего NSArray
, я устанавливаю соответствующий слот сетки в NULL
.
То есть двумерный массив (сетка) — это просто набор быстрых (но тупых) указателей на объекты, безопасно сохраненные где-то еще (NSArray
ivar).
Есть ли способ обойти это с помощью приведения типов? Например, определите и разместите мою сетку как:
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;