ARC and @synthesize of read only property

When I'm trying to synthesize a read only property in obj-c, I get the following error.

error: ARC forbids synthesizing a property of an Objective-C object with unspecified storage attribute [4]

I understand why it is necessary to specify storage attribute to generate a setter, but why is it relevant to generate a getter ?

Just in case, here is a simple test case:

@interface Foo { id _ivar; }
@property(nonatomic, readonly) id ivar;
@end
@implementation Foo
@synthesize ivar = _ivar;
@end

Trying to compile this code using -fobjc-arc fails.

-- Jean-Daniel

The getter semantics also change:

- If the property is retained, then it will retain / autorelease the object, to ensure that it is not deallocated prematurely.

- If the property is weak, then it must use the weak read barrier function

- If the property is unsafe_unretained, then the getter will just return it directly.

Even in ARC mode, the compiler can't magically guess what you mean.

David

When I'm trying to synthesize a read only property in obj-c, I get the following error.

error: ARC forbids synthesizing a property of an Objective-C object with unspecified storage attribute [4]

I understand why it is necessary to specify storage attribute to generate a setter, but why is it relevant to generate a getter ?

The getter semantics also change:

- If the property is retained, then it will retain / autorelease the object, to ensure that it is not deallocated prematurely.

- If the property is weak, then it must use the weak read barrier function

- If the property is unsafe_unretained, then the getter will just return it directly.

Thank you for the explanation. So the retained/autorelease is a new behavior introduced with ARC. AFAIK, the getter did this only for atomic properties in non ARC mode.

Even in ARC mode, the compiler can't magically guess what you mean.

While it cannot always guess, when the @synthezise directive specify an ivar, it can default to the ivar ownership, as this is the only acceptable value.

-- Jean-Daniel

The simple answer is that this code defaulted to being an "assign" property before, and that dangerous because it quickly leads to a dangling pointer. ARC forces you to make a choice: strong, weak, unsafe_unretain, etc.

-Chris

Thank you for the explanation. So the retained/autorelease is a new behavior introduced with ARC. AFAIK, the getter did this only for atomic properties in non ARC mode.

You can check the generated IR. In ARC mode, it calls objc_getProperty() for atomic properties. For nonatomic properties, it accesses the ivar directly and calls objc_retainAutoreleaseReturnValue(). If you do something like:

id o = [object synthesizedNonatomicProperty];

Then ARC will translate this into something like:

o = objc_retainAutoreleasedReturnValue([object synthesizedNonatomicProperty]);

This skips the autorelease pool, so the object is now retained in the caller but not present in the autorelease pool. ARC will then objc_release() it at the end of the scope of o. This means that you get a lot less redundant autorelease pool churn in ARC mode.

Even in ARC mode, the compiler can't magically guess what you mean.

While it cannot always guess, when the @synthezise directive specify an ivar, it can default to the ivar ownership, as this is the only acceptable value.

Ivars all default to __strong, but it sounds like you actually want unsafe_unretained (which would then simply be objc_retain()'d in the caller in ARC mode).

David

Thank you for the explanation. So the retained/autorelease is a new behavior introduced with ARC. AFAIK, the getter did this only for atomic properties in non ARC mode.

You can check the generated IR. In ARC mode, it calls objc_getProperty() for atomic properties. For nonatomic properties, it accesses the ivar directly and calls objc_retainAutoreleaseReturnValue(). If you do something like:

id o = [object synthesizedNonatomicProperty];

Then ARC will translate this into something like:

o = objc_retainAutoreleasedReturnValue([object synthesizedNonatomicProperty]);

This skips the autorelease pool, so the object is now retained in the caller but not present in the autorelease pool. ARC will then objc_release() it at the end of the scope of o. This means that you get a lot less redundant autorelease pool churn in ARC mode.

That make sense. Thanks again.

Even in ARC mode, the compiler can't magically guess what you mean.

While it cannot always guess, when the @synthezise directive specify an ivar, it can default to the ivar ownership, as this is the only acceptable value.

Ivars all default to __strong, but it sounds like you actually want unsafe_unretained (which would then simply be objc_retain()'d in the caller in ARC mode).

I really have and want a strong ivar. Declaring it as 'unsafe_unretained' will prevent its releasing in the generated object's destructor.
So the solution in my case it to change the property declaration to tell the compiler it is a retained property.

-- Jean-Daniel

Look like commit 135747 changed this behavior for nonatomic (and non-weak) property. They now have the same behavior in ARC mode than in non-ARC mode. They are simply returned.

-- Jean-Daniel

Thank you for the explanation. So the retained/autorelease is a new behavior introduced with ARC. AFAIK, the getter did this only for atomic properties in non ARC mode.

You can check the generated IR. In ARC mode, it calls objc_getProperty() for atomic properties. For nonatomic properties, it accesses the ivar directly and calls objc_retainAutoreleaseReturnValue(). If you do something like:

id o = [object synthesizedNonatomicProperty];

Then ARC will translate this into something like:

o = objc_retainAutoreleasedReturnValue([object synthesizedNonatomicProperty]);

This skips the autorelease pool, so the object is now retained in the caller but not present in the autorelease pool. ARC will then objc_release() it at the end of the scope of o. This means that you get a lot less redundant autorelease pool churn in ARC mode.

That make sense. Thanks again.

Even in ARC mode, the compiler can't magically guess what you mean.

While it cannot always guess, when the @synthezise directive specify an ivar, it can default to the ivar ownership, as this is the only acceptable value.

Ivars all default to __strong, but it sounds like you actually want unsafe_unretained (which would then simply be objc_retain()'d in the caller in ARC mode).

I really have and want a strong ivar. Declaring it as 'unsafe_unretained' will prevent its releasing in the generated object's destructor.
So the solution in my case it to change the property declaration to tell the compiler it is a retained property.

This changed in r136155, now there will only be an error if the backing ivar is not user declared and there is no ownership attribute on the type.

-Argyrios

Thank you :slight_smile:

-- Jean-Daniel