Подтвердить что ты не робот

Strong @property с __attribute __ ((NSObject)) для типа CF не сохраняется

ОБНОВЛЕНИЕ: эта проблема исправлена ​​с Xcode 4.6!

Этот метод теперь работает по назначению. Однако, прежде чем использовать его в своем коде, обязательно прочитайте заметки в верхней части Роба Напира.

ОРИГИНАЛЬНАЯ ПОЧТА

(ARC, Xcode 4.3.1, iOS 5.1)

У меня есть сильное свойство типа CF (CGImage), которое я хочу автоматически управлять с помощью ARC с помощью __attribute__((NSObject)) (как при сохранении и выпуске в синтезированном сеттере, так и в nall'ed в dealloc) но он не работает: объект не сохраняется при назначении свойства.

Минимальный пример воспроизведения:

@interface TestClass : NSObject
@property (nonatomic, strong) __attribute__((NSObject)) CFStringRef str;
@end

// ...In some function
CFStringRef str = (__bridge CFStringRef)[NSString stringWithFormat:@"%g", 2.5];
NSLog(@"%ld", CFGetRetainCount(str));
TestClass *obj = [[TestClass alloc] init];
obj.str = str;
NSLog(@"%ld", CFGetRetainCount(str));

Что печатает "1" дважды.

Теперь странно то, что (хотя я не уверен в этом), я думаю, что он работал правильно, прежде чем я обновился до iOS 5.1 и Xcode 4.3.1 (от iOS 5 и Xcode 4.2), и с ним переключился с gdb к lldb. Может ли кто-нибудь, кто не обновил (или знает, как изменить обратно компилятор), может подтвердить?

4b9b3361

Ответ 1

EDIT2 (март 2013 г.) FYI для тех, кто интересуется этой техникой, Документация ARC для clang включает следующее примечание

Использование __attribute__((NSObject)) typedefs не рекомендуется. Если его абсолютно необходимо использовать этот атрибут, будьте предельно явным в использовании typedef и не предполагайте, что он будет сохранен языковыми функциями, такими как __typeof и заменой аргументов шаблона С++.

Обоснование

Любая операция компилятора, которая, кстати, накладывает тип "сахар" на тип, даст тип без атрибута, что может привести к неожиданному поведению.


РЕДАКТИРОВАТЬ Ниже представлено интересное, но, вероятно, неуместное. Это ошибка, и вы должны открыть радар. Как отметил @lnafziger, это законно и должно быть выполнено. Ошибка в том, что она не соблюдается, если вы включаете nonatomic. Если вы удалите nonatomic, то он будет работать. Ничто в определении nonatomic не предполагает, что это по дизайну.


Это своего рода умный, но я думаю, я понимаю, почему он не работает. Вы можете подтвердить, кстати, что он не работает, генерируя ассемблер и отмечая, что setStr: не вызывает objc_storeStrong(). Он выполняет простое назначение.

Проблема заключается в том, что ваше определение свойства не соответствует определению сохраняемого указателя объекта (выделение добавлено):

Сохраняемый указатель объекта (или сохраняемый указатель) является значением сохраняемый тип указателя объекта (сохраняемый тип). Есть три типы сохраняемых типов указателей объектов:

  • указатели блоков (сформированные путем применения синтаксиса объявления каретки (^) к тип функции)
  • Objective-C указатели объектов (id, класс, NSFoo * и т.д.)
  • typedefs, отмеченный __attribute __ ((NSObject))

Создал ли typedef как указано? Нет, ты не сделал. Хорошо, как мы это сделаем?

typedef __attribute__((NSObject)) CFStringRef MYStringRef;

@interface TestClass : NSObject
@property (nonatomic, strong) MYStringRef str;
@end

... the rest of your code ...

Это будет печатать "1", а затем "2", как я предполагаю, вы ожидаете. Меня пугает по неуказанным причинам, но, глядя на выход ассемблера, все кажется прекрасным, и я не могу придумать какой-либо конкретной проблемы или нарушения здесь.

Вы можете быть оправданы при открытии радара для этого. Тот факт, что typedef не обрабатывается так же, как указанный тип, удивляет хотя бы, даже если документирован.

EDIT: Отметив комментарий @lnafziger из языка программирования ObjC, в ARC определенно есть ошибка spec/реализация или ошибка в связанном документе, поэтому один из них должен быть исправлен.