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

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.

Related

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's the difference the member variable between in a interface and #property (nonatomic, strong)?

#interface ChargeView (){
NSString* billid;
int clickRow;
NSMutableArray *arr1;
}
#property (nonatomic, strong) NSMutableArray *arr2;
What's the difference between arr1 and arr2? Which is better or write it anywhere if I like?
The property also generates the accessors -(NSMutableArray *)arr2 (getter) and -(void)setArr2:(NSMutableArray *)arr2 (setter). It further generates a corresponding instance variable _arr2 (the underscore is convention for ivars). The attributes of the property determine the behavior of the accessors. For instance, if the property is marked atomic, the accessors will synchronize access to the ivar.
On the other hand, arr1 is just an ivar and you have to write accessors (if you need any) yourself.

Does an instance variable also get default property attributes?

If I declare an instance variable
#implementation Person {
NSString *name; // would this be atomic, strong, readwrite?
}
Does it get the same default attributes as if I declared it a property (atomic, strong, readwrite)
#interface Person()
#property NSString *name; // would be atomic, strong, readwrite by default
#end
ivars and local variables are strong by default (under ARC). Variables are read-write unless the appropriate use of const is applied. And variable access is non-atomic unless specific steps are taken to make the access atomic.
So essentially, ivars and local variables behave as strong, non-atomic, read-write.
Nope. Instance variables don't get attributes like atomic, strong, etc., at all -- those are only attributes that apply to properties. (If you're using ARC, they'll be treated as a strong variable, though.)

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.

iOS readonly and retain are mutually exclusive

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.