__attribute__((NSObject)) 自动合成的 属性 没有在 dealloc 中释放

__attribute__((NSObject)) auto-synthesized property doesn't get released in dealloc

我想要一个由强引用支持但在 ARC 中具有 Core Foundation 对象类型(而不是 Objective-C 对象类型)的 属性。我相信这样做的正确方法是用 __attribute__((NSObject)) 标记它,ARC 将像 Objective-C 对象类型 属性 一样管理它(即释放并保留分配,并释放时包含对象是 dealloced):

@interface Foo : NSObject
@property (nonatomic, strong) __attribute__((NSObject)) CFArrayRef bar;
@end

@implementation Foo
// property bar is auto-synthesized
@end

(我知道 CFArray 是免费桥接到 NSArray 的。这只是为了举例。真正的用例是针对没有收费的 Core Foundation 类型-免桥接。)

但是当我将对象放入 Foo 对象的 bar 属性 并让 Foo 对象超出范围并得到 dealloced,bar 中的对象被泄露,因为当 Foo 对象被释放时它没有被释放,就像使用常规 Objective-C 对象类型 属性:

void someFunc(void) {
  Foo *foo = [[Foo alloc] init];
  CFArrayRef arr = CFArrayCreateMutable(NULL, 42, &kCFTypeArrayCallBacks);
  foo.bar = arr;
  CFRelease(arr);
}

代码编译时没有任何警告或错误,并且顺利通过了分析。 Leaks 工具检测到可变数组已泄漏。

这是编译器错误吗?我使用的是最新的 Xcode (8.3.3).

ARC specification中有奇怪的写法,在定义retainable object pointer时,最后一种定义为:

typedefs marked with __attribute__((NSObject))

请注意,这使用 typdefs 而不是 declarations。该措辞在规范中再次使用了一点。这 almost 似乎建议您需要使用 typedef 来识别属性,这将是一个奇怪的设计。

不幸的是,当涉及到 属性 声明时,规范说(强调):

Applying __attribute__((NSObject)) to a property not of retainable object pointer type has the same behavior it does outside of ARC: it requires the property type to be some sort of pointer and permits the use of modifiers other than assign. These modifiers only affect the synthesized getter and setter; direct accesses to the ivar (even if synthesized) still have primitive semantics, and the value in the ivar will not be automatically released during deallocation.

这似乎确实可以解释您所看到的行为 - 设计是半生不熟的,getter/setter 采用了语义但释放没有。

鉴于规范措辞,您对自动支持的一个希望似乎是首先为 CF 类型创建一个属性 typedef,然后在 属性 声明中使用它...如果为真则很奇怪,但它符合奇怪的措辞...抱歉目前无法检查,但我猜结果会令人失望。尝试将 nil 分配给 dealloc 中的 属性,因为它使用 setter(根据规范)具有正确的语义。

HTH