C-стиль массива указателей на Objective-C объекты под ARC

У меня есть 2D массив указателей на экземпляры Objective-C для отслеживания игровых объектов на сетке карт. Теперь я переношу свой код в ARC, и Xcode указал на ошибку. Я знал, что указатели на объекты не допускаются как члены структуры, но этот меня поймал (почти) от страха.

Я понимаю обоснование ограничений ARC, но:

  • Я не могу позволить себе накладные расходы массивов Objective-C при поиске объектов в сетке и

  • Сами объекты уже принадлежат NSArray ivar, определенным в том же классе, который имеет сетку C-стиля в качестве ivar; массив c-style - это только удобно структурированный ярлык. Более того, когда объекты удаляются из владельца NSArray, я устанавливаю соответствующий интервал сетки на NULL.

То есть 2D-массив (сетка) представляет собой просто набор быстрых (но немых) указателей на объекты, сохраненные где-то в другом месте (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;

При доступе к объекту at (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;

Ответ 1

Обход ARC с использованием отбросов - это, как правило, плохая идея. Лучшим способом было бы отключить ARC для вашего map.m(или вырвать только часть поиска в отдельный класс). Затем ручное управление памятью внутри него с помощью retain/release и структуры C, которые вам нравятся, если вы делаете это правильно, это будет нормально работать, и вы сможете вызвать его из других классов, избегая накладных расходов вложенных NSArrays и т.д.