Retained Core Foundation Property

2019-02-04 15:43发布

(Xcode 4.2, iOS 5, ARC)

I have some properties of Core Foundation (/Graphics) objects that should take ownership of their objects. Now in these Apple docs I found this:

In OS X v10.6 and later, you can use the __attribute__ keyword to specify that a Core Foundation property should be treated like an Objective-C object for memory management: @property(retain) __attribute__((NSObject)) CFDictionaryRef myDictionary;

Unfortunately I couldn't find any elaboration on this. I'm using this:

@property (nonatomic, strong) __attribute__((NSObject)) CGImageRef loupeImage;

And it seems to work the way I'd expect. It retains the object on setting the property and releases it when I set the property to nil.

Now my question is, do I still need to explicitly set those properties to nil in my dealloc?

2条回答
劫难
2楼-- · 2019-02-04 16:35

Edit: My previous post was incorrect. __attribute__((NSObject)) on the property only causes it to retain/release the property when using the property accessors. It does not affect access to the ivar, and notably, it does not nil out (or release) the property in dealloc. So yes, in your dealloc you either need to say self.loupeImage = nil; or you need to say [_loupeImage release].


Original post:

If the compiler accepts the strong keyword, then it's going to treat it correctly, retaining and releasing as expected, and nilling out automatically in ARC. The whole idea of __attribute__((NSObject)) is it tells the compiler to treat this object exactly as if it were an obj-c object, and so that's what it does.

So no, you shouldn't have to explicitly nil them out in dealloc. You'll get the default ARC behavior of nilling/releasing automatically.

查看更多
ゆ 、 Hurt°
3楼-- · 2019-02-04 16:37

Now my question is, do I still need to explicitly set those properties to nil in my dealloc?

Yes, you do, with the declaration you showed.

In the Property declarations section of the ARC specification, it says:

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.

(emphasis on last part added by me)

In other words, applying __attribute__((NSObject)) and strong on a property with Core Foundation type makes the getters and setters work correctly, but it will not make ARC manage the underlying instance variable (because the instance variable's type will still be the Core Foundation type), and thus ARC will not release the instance variable upon dealloc if it is non-nil. With such a property declaration, you will have to nil it in dealloc or cause a leak.

However, there is a way to make ARC manage the variable itself. Since the variable has a Core Foundation type, you can make it an ARC-managed type by wrapping it in a typedef with __attribute__((NSObject)).

The Retainable object pointers section of the ARC specification says:

There are three kinds of retainable object pointer types:

  • block pointers (formed by applying the caret (^) declarator sigil to a function type)
  • Objective-C object pointers (id, Class, NSFoo*, etc.)
  • typedefs marked with __attribute__((NSObject))

(emphasis on last item added by me)

So if you make a typedef like this:

typedef __attribute__((NSObject)) CGImageRef MyImageRef;

and declare your property like this:

@property (nonatomic, strong) MyImageRef loupeImage;

the underlying variable will be managed by ARC (because the underlying variable will have the typedef'd type, which is an ARC-managed type) and you will not have to nil it in dealloc.

查看更多
登录 后发表回答