iOS readonly and retain are mutually exclusive - objective-c

I want to have a strong readonly property. When I use this code:
#property (strong, nonatomic, readonly) NSString *test;
I get a warning: "Property attributes 'readonly' and 'retain' are mutually exclusive". How can I solve this warning?

Create a property in your continuation category which redefines the variable as readwrite:
#property (strong, nonatomic, readwrite) NSString *test;
Now, publicly the property is read only, but privately you can write it. The compiler will generate the methods you need and allow you to call them.

Related

Why does ARC conversion add "weak" decorator to "readonly" properties?

I'm just updating a really old project to ARC (2017 – I know).
I've noticed that for readonly property declarations, it's adding a weak decorator. Eg:
// Before conversion to ARC:
#property (nonatomic, readonly) NSString *defaultName;
// After conversion to ARC:
#property (weak, nonatomic, readonly) NSString *defaultName;
Could someone explain why it's doing this?
There are a few SO questions and answers about the meaning of weak, strong and copy when applied to a readonly property. An example is this which seems to be directly contradicted by this – I don't really see how it makes sense as they only seem to apply on setting a property and a readonly has an explicit getter method.
Before the introduction of ARC, the default memory attribute was assign, therefore
#property (nonatomic, readonly) NSString *defaultName;
was the same as
#property (nonatomic, assign, readonly) NSString *defaultName;
That should explain you why ARC migration uses weak.
This changed when ARC was introduced - for object types strong/retain became the default.
This attribute affects only the setters anyway, therefore for readonly properties the attribute can have any value.

In case of #property without ivar what's difference between strong, weak and assign?

I want to declare #property without ivar. Is there any difference if I declare #property with strong, weak or assign ?
The #property declaration defines a contract with the user's of the property. If it is declared as weak, for example, then the user of the property knows that the passed object won't be retained.
This contract should be true whether the property is backed by an ivar or not.
In your case, the property should be strong, weak, or assign depending on your implementation of your property and the contract you wish to provide for the property.
It depends of what type the property is. For example for primitive types like NSInteger you can't declare property with strong or weak attributes. Xcode will show you an error.
So these declarations are invalid:
#property (nonatomic, strong) NSInteger max;
#property (nonatomic, weak) NSInteger max;
#property (nonatomic, copy) NSInteger max;
because strong, weak and copy are attributes of object types and NSInteger isn't object type. It's primitive type. Thus, following declaration is valid:
#property (nonatomic, assign) NSInteger max;
Attributes assign, weak, strong, copy and unsafe_unretained specify memory management rules for ivar that is backed by property. So if you are not going to create ivar for property (suppose you want to provide your own getter/setter and property will not store any value) it doesn't matter what attribute you'll specify. But as I mentioned above you couldn't specify attributes of object types for primitive types.

What does this objective-c property synthesis warning mean?

Since upgrading to Xcode 5.1, I'm starting to see the following warning in some code my project uses. I'm trying to figure out what it means.
Warning: Auto property synthesis will not synthesize property 'responseHeader' because it is 'readwrite' but it will be synthesized 'readonly' via another property
The code where it's occurring, in the .m file:
#interface S3Response ()
#property (nonatomic, readwrite, retain) NSDictionary *responseHeader;
#end
The previous declaration of the property, in the .h file:
#property (nonatomic, readonly) NSDictionary *responseHeader;
There is no #synthesize statement for that property, nor are responseHeader or setResponseHeader defined as methods. There is however an explicit definition of an ivar named responseHeader.
Seems pretty straightforward to me: property is declared as read-only for users of the class, but read-write locally so the class can set it.
What does this warning mean, and what should I do about it?
That code seems to be from the AWS SDK for iOS,
and S3Response is a subclass of AmazonServiceResponse.
The public AmazonServiceResponse interface defines a read-only property
#interface AmazonServiceResponse:NSObject
// ...
#property (nonatomic, readonly) NSDictionary *responseHeader;
#end
which is redefined as read-write in a class extension in the implementation file:
#interface AmazonServiceResponse ()
#property (nonatomic, readwrite, retain) NSDictionary *responseHeader;
#end
Now the subclass S3Response also wants read-write access to this property,
and therefore also defines in the class extension of its implementation file:
#interface S3Response ()
#property (nonatomic, readwrite, retain) NSDictionary *responseHeader;
#end
The compiler complains because – when compiling "S3Response.m" – it does not know
that a setter for the property exists in the superclass (it does not read
the implementation file of the superclass at that point). Also the compiler cannot
simply synthesize a setter in the subclass, because it cannot not know that the
property is backed-up by an instance variable in the superclass.
But you know that a setter will be generated, so you can remove the warning by
adding a #dynamic declaration to the subclass implementation:
#implementation S3Response
#dynamic responseHeader;
...
#dynamic is a "promise" to the compiler that all necessary accessor methods will
be available at runtime.
The problem here is as follows.
By default, if don't write ownership (weak/retain/strong/assign) explicitly, xCode will check the type automatically. So in case of NSDictionary it will be strong. Thus, in interface you will have
#property (nonatomic, readonly, strong) NSDictionary *responseHeader;
Then it will be contradict you private implementation definition
#property (nonatomic, readwrite, retain) NSDictionary *responseHeader;
Compilator doesn't match strong and retain under property synthesizing though it is formally the same thing.
To cure situation you can write retain in both cases, or more correct, you should not write retain at all. It will be strong by default in both definitions.

Why give a property both readonly and assign?

If assign is a setter, but a property is readonly, then it will not be doing any setting, so why use assign ?
I am getting this from the Apple docs on class extensions. In this page, I get why you'd want a public readonly property, then make it privately readwrite, but then why not omit the assign from the public #interface and just include it in the class extension only?
If you declare a #property multiple times (typically because you declare a public readonly property in the header file, and a readwrite property in an anonymous category in your .m), the memory management schemes have to match.
So if you have this in your .m:
#property (assign, readwrite) NSObject *foo;
Then you need this in your header, and the assign is mandatory:
#property (assign, readonly) NSObject *foo;
If you leave just (nonatomic), the compiler will automatically set the second parameter to assign.

Objective-C accessor declarations (readonly, readwrite, etc)

In the book, "Cocoa Design Patterns," the author sometimes declares a property in the #interface as readonly:
// .h
#property (readonly, copy) NSArray *shapesInOrderBackToFront;
and then later adds an unnamed category to the implementation (.m) file like this:
// .m
#interface MYShapeEditorDocument ()
#property (readwrite, copy) NSArray *shapesInOrderBackToFront;
#end
Any idea as to why? It's unclear to me how this approach is better than, or more necessary than, initially declaring the property as "readwrite".
Externally the property will be readonly. While inside the class it will have both the accessor, and the setter.
The setter will not be visible by the compiler outside of the implementation(.m) file.