マップグリッド上のゲームオブジェクトを追跡するために、Objective-Cインスタンスへのポインターの2D配列があります。現在、コードを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;
(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;
マップオブジェクトは、ゲームの開始時に1回作成され、ゲームの進行状況に応じて削除されます。マップオブジェクトを別のオブジェクトに置き換える必要がある場合は、次のようにします。
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;