Как безопасно хранить объект id в элементе С++ void * в ARC, когда другие объекты не привязаны к объекту? - программирование
Подтвердить что ты не робот

Как безопасно хранить объект id в элементе С++ void * в ARC, когда другие объекты не привязаны к объекту?

Я работаю с Box2D (С++) и создаю объект Objective-C и назначаю его свойству body2D body userData, имеющему тип void*.

Теперь в некоторых случаях void* userData может быть единственной активной ссылкой на объект ObjC. Поэтому, поскольку я использовал (__bridge void*) в задании, ARC разрешает это. Это то, что мне нужно исправить.

Я размышлял над вариантами, чтобы это не происходило? Я читал документацию Clang ARC, в частности, части о литье мостов (а также Q & A на SO), а также кивнул различным конструкциям литья моста, которые они считают "плохо сформирован".

Тем не менее, моя первая мысль заключалась в использовании (__bridge_retained void*) в первоначальном назначении userData. Но это заставило меня задуматься о том, как сохранить равновесие? Я, очевидно, не могу отправить релиз объекту.

Так должен ли я CFRelease() объект? Или это должно быть CFBridgingRelease()? Или оба незаконны здесь?

Является ли (__bridge_transfer void*) отличным от userData до временного типа идентификатора достаточно, возможно, при установке userData в NULL? Это даже хорошая идея?

Я знаю, что альтернативой было бы сохранить отдельный NSArray/NSDictionary для объектов userData и синхронизировать их с временем жизни тела Box2D, добавляя и удаляя их в синхронизации с их телами Box2D.

Но это кажется излишним, потому что здесь я знаю, что я делаю, я знаю, что мне нужно +1 объект до тех пор, пока тело Box2D активно, и -1 объект, когда тело Box2D удалено, Плюс я знаю, что есть только два метода, когда тела Box2D добавляются и удаляются, а прямой доступ к userData в моей структуре даже невозможен, потому что все объекты Box2D скрыты за интерфейсами Objective-C/wrappers.

Положив, возможно, "плохо сформированный" в сторону на мгновение, что бы вы порекомендовали мне в этой ситуации?

4b9b3361

Ответ 1

__bridge_retained означает "Отправить этот объект ARC в землю без ARC, сохранив его". Вы называете это, когда вам нужно создать "untracked" void *. Итак, в вашем случае userData = (__bridge_retained void *)obj.

__bridge_transfer означает "вытащите этот объект из земли без ARC, выпустив его". Вы называете это, когда хотите эффективно аннулировать void *. Итак, obj = (__bridge_transfer id)userData. После этого указатель userData небезопасен для использования; вместо этого вы работаете только с obj. Когда obj выходит за пределы области действия, ARC выпустит его в последний раз. Это может привести к созданию временного id исключительно для этой цели.

Итак, в вашем случае вы хотите использовать __bridge_retained, когда вы отправляете объект в Box2D, и используйте __bridge_transfer, если вы хотите сделать недействительным userData. Если вам нужно получить доступ к userData как объект Objective-C, но не сделать недействительным указатель, используйте plain __bridge.

Ответ 2

Вы неправильно поняли, что автор документации имел в виду "плохо сформированный". Это плохо сформировано:

NSData* data; // Initialized
NSData* data2= (__bridge NSData*) data;

Также это плохо сформировано:

void* data; // Initialized
void* data2= (__bridge void*) data;

Это не плохо сформировано:

NSData* data; // Initialized
void* data2= (__bridge void*) data;

Чтобы не было плохо сформировано, достаточно, чтобы левое значение сохранялось, а правильное значение не сохранялось, или наоборот. Поэтому, поскольку в вашем случае ваши указатели на объекты объектов указывают на исходные указатели и наоборот, ваш подход правильный.

В вашем месте я бы использовал интеллектуальный указатель, который отправляет сообщение CFBridgingRetain в конструирование, и сообщение CFBridgingRelease об уничтожении.