strong @property с __attribute __ ((NSObject)) для типа CF не сохраняет - PullRequest
21 голосов
/ 13 марта 2012

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

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

ОРИГИНАЛЬНЫЙ ПОЧТА

(ARC, Xcode 4.3.1, iOS 5.1)

У меня есть сильное свойство типа CF (CGImage), которым я хочу, чтобы ARC автоматически управлял им с помощью __attribute__((NSObject)) (например, при наличии retain & release в синтезированном сеттере и обнулении его в 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 в лдб. Может кто-то, кто не обновил (или знает, как вернуть обратно компилятор), может подтвердить?

1 Ответ

33 голосов
/ 13 марта 2012

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

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

Обоснование

Любая операция компилятора, которая случайно удаляет тип «sugar» из типа, приведет к типу без атрибута, что может привести к неожиданному поведению.


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


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

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

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

  • блочные указатели (сформированные путем применения сигилла объявления caret (^) к типу функции)
  • Указатели объектов Objective-C (id, Class, 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 не обрабатывается так же, как указанный тип, по меньшей мере удивителен, даже если задокументирован.

РЕДАКТИРОВАТЬ: С учетом комментария @ lnafziger из ObjC Programming Language , определенно есть либо ошибка в спецификации / реализации ARC, либо ошибка в связанном документе, поэтому одну из них следует исправить.

...