简体   繁体   中英

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

I want a property backed by a strong reference but which has a Core Foundation object type (not Objective-C object type) in ARC. I believe the proper way to do this was to mark it with __attribute__((NSObject)) and ARC will manage it just like an Objective-C object type property (ie release and retain on assign, and release when the containing object is dealloc ed):

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

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

(I know CFArray is toll-free bridged to NSArray . This is just for the sake of an example. The real use case is for a Core Foundation type that does not have toll-free bridging.)

But when I put an object into the bar property of a Foo object and let the Foo object go out of scope and get dealloc ed, the object in bar is leaked because it is not released when the Foo object is deallocated, as it would with a regular Objective-C object type property:

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

The code compiles without any warnings or errors, and passes Analyze with no issues. The Leaks instrument detects that the mutable array was leaked.

Is this a compiler bug? I am using the latest Xcode (8.3.3).

There is curious wording in the ARC specification , when defining retainable object pointer the last kind is defined as:

typedefs marked with __attribute__((NSObject))

Note that this uses typdefs and not declarations . The phrasing is used again a little further in the spec. This almost seems to suggest you need to use a typedef for the attribute to be recognised, which would be a curious design.

Unfortunately when it comes to property declarations the spec says (emphasis added):

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 .

This does appear to explain the behaviour you are seeing - the design is half-baked, the getter/setter adopt the semantics but deallocation doesn't.

Given the spec wording your one hope for automatic support seems to be to first create an attributed typedef for CF type and then use that in the property declaration... Weird if true, but it fits the curious wording... Sorry can't check this at the moment, but I'm guessing disappointment will be the outcome. Try assigning nil to the property in the dealloc as that uses the setter which (according to the spec) has the correct semantics.

HTH

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM