对于CF类型,带有__attribute __((NSObject))的强大@property不会保留

时间:2012-03-13 13:31:50

标签: objective-c ios automatic-ref-counting core-foundation

更新:此问题自Xcode 4.6起已修复!

此技术现在再次按预期工作。但是,在您的代码中使用之前,请务必阅读Rob Napier优秀答案顶部的注释。

原始帖子

(ARC,Xcode 4.3.1,iOS 5.1)

我有一个CF类型(CGImage)的强大属性,我希望ARC使用__attribute__((NSObject))自动管理(就像在合成的setter中保留和释放一样,并且它没有在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。未升级(或知道如何更改编译器)的人可能会确认吗?

1 个答案:

答案 0 :(得分:33)

EDIT2(2013年3月)对于对此技术感兴趣的人,ARC documentation for clang包含以下注释:

  

不建议使用__attribute__((NSObject)) typedef。如果绝对有必要使用此属性,请非常明确地使用typedef,并且不要假设它将由__typeof和C ++模板参数替换等语言功能保留。

     

<强>原理

     

任何偶然从类型中删除类型“sugar”的编译器操作都会产生一个没有属性的类型,这可能会导致意外行为。


编辑以下内容很有趣,但可能无关紧要。这是一个错误,你应该打开一个雷达。正如@lnafziger所指出的那样,这是合法的,应该受到尊重。问题在于,当您加入nonatomic时,它不会受到尊重。如果您删除nonatomic,那么它可以正常运行。 nonatomic定义中没有任何内容表明这是设计的。


这有点聪明,但我想我明白为什么它不起作用。您可以通过生成汇编程序并注意setStr:不调用objc_storeStrong()来确认它无法正常工作。它做了一个简单的分配。

问题是你的属性定义不符合可保留对象指针的定义(强调添加):

  

可保留对象指针(或可保留指针)是a的值   可保留对象指针类型(可保留类型)。有三种   各种可保留的对象指针类型:

     
      
  • 块指针(通过将插入符号(^)声明符sigil应用于a   功能类型)
  •   
  • Objective-C对象指针(id,Class,NSFoo *等)
  •   标有__attribute __((NSObject))的
  • typedefs
  •   

您是否按指定创建了typedef?不,你没有。好的,那我们怎么做呢?

typedef __attribute__((NSObject)) CFStringRef MYStringRef;

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

... the rest of your code ...

这将打印“1”,然后打印“2”,因为我认为你期望。因为未指明的原因让我害怕,但看着汇编输出,一切似乎都很好,我不能想到任何具体问题或违规行为。

你可能有理由为此打开雷达。即使记录,typedef的处理方式与指定类型不同,这一事实至少令人惊讶。

编辑:注意来自ObjC Programming Language的@ lnafziger的评论,无论是ARC规范/实现中的错误还是链接文档中的错误,因此其中一个应该是固定的。