What does this objective-c property synthesis warning mean? - objective-c

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.

Related

Hiding implementation details with .h and .m in objc

I'm confused about something. If in your .h file you have:
#property (nonatomic, strong, readonly) NSArray *categories;
and then in the .m you have:
#interface MyClass ()
#property (nonatomic, strong, readwrite) NSMutableArray *categories;
#end
If I want to later set categories in the .m file, I can do:
[self setCategories:[NSArray arrayWithArray:categories]];
But then Xcode complains that incompatible pointer types sending NSArray to NSMutableArray. I'm basically trying to hide the implementation details and have the .m use a NSMutableArray and to a consumer
use an NSArray.
[self setCategories:[NSMutableArray arrayWithArray:categories]]; // this gives no Xcode warning
By using the [NSMutableAray arrayWithArray:] method, does it still prevent the consumer of my Class from mutating my categories array?
You've done all you can in objc.
Your internal readwrite declaration needs a mutable array, so Xcode's complaining is right, you have to use a mutable for the setter.
The consumer can do everything with that object, even if it's declared as NSArray you can find out it's a NSMutableArray in reality and change it.
You can't prevent that. But your public declaration shows it should be assumed immutable. There's nothing more you can do.

Can the memory management of a property change if it's redefined in a class extension?

If I have a property like this:
//test.h
#interface test
#property (nonatomic, readonly, weak) NSObject x;
#end
redefined in the implementation file to be read/write:
// test.m
#interface test ()
#property (nonatomic, readwrite) NSObject x;
#end
I used weak in .h, but I said nothing in the extension, will the property keep the 'weak' specifier, or will it change to 'strong'?
Will the keywords strong/assign/weak be overwritten when the property is redefined?
A simple test with Xcode 5.1.1 shows the weak attribute is kept. The same is true for the assign and strong attributes - you can specify them in the .h and omit them in the .m, if you do include them in the .m the two must match.
Having said that, I do not know if this is documented anywhere. But then the semantics of Objective-C are not formally defined anywhere either. So use at your own risk.
Recommendation: just repeat it.

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.

Objective-C: How do you access parent properties from subclasses?

If I have this class defined, how do I access the someObject property in subclasses without compiler errors?
#interface MyBaseClass
// someObject property not declared here because I want it to be scoped
// protected. Only this class instance and subclass instances should be
// able to see the someObject property.
#end
// This is a private interface extension...properties declared here
// won't be visible to subclasses. However, I don't see any way to
// declare protected properties...
#interface MyBaseClass (private)
#property (nonatomic, readwrite, retain) NSObject *someObject;
#end
#interface MySubclass : MyBaseClass
#end
#implementation MySubclass
- (id) init {
// Try to do something with the super classes' someObject property.
// Always throws compile errors.
// Semantic Issue: Property 'someObject' not found
// object of type 'MySubclass *'
self.someObject = nil;
}
#end
I'm obviously not understanding how inheritance works in objective-c. Could someone enlighten me?
The solution you're after is to declare the MyBaseClass private property in a class extension:
#interface MyBaseClass ()
#property (nonatomic, readwrite, retain) NSObject *someObject;
#end
You are then free to make that declaration both in MyBaseClass and in MySubclass. This lets MySubclass know about these properties so that its code can talk about them.
If the repetition bothers you, put the class extension in a .h file of its own and import it into both .m files.
I will give an example from my own code. Here is MyDownloaderPrivateProperties.h:
#interface MyDownloader ()
#property (nonatomic, strong, readwrite) NSURLConnection* connection;
#property (nonatomic, copy, readwrite) NSURLRequest* request;
#property (nonatomic, strong, readwrite) NSMutableData* mutableReceivedData;
#end
There is no corresponding .m file and that's all that's in this file; it is, as it were, purely declarative. Now here's the start of MyDownloader.m:
#import "MyDownloader.h"
#import "MyDownloaderPrivateProperties.h"
#implementation MyDownloader
#synthesize connection=_connection;
#synthesize request=_request;
#synthesize mutableReceivedData=_mutableReceivedData;
// ...
And here's the start of its subclass MyImageDownloader.m:
#import "MyImageDownloader.h"
#import "MyDownloaderPrivateProperties.h"
Problem solved. Privacy is preserved, as these are the only classes that import MyDownloaderPrivateProperties.h so they are the only classes that know about these properties as far as the compiler is concerned (and that's all that privacy is in Objective-C). The subclass can access the private properties whose accessors are synthesized by the superclass. I believe that's what you wanted to accomplish in the first place.
that's how you access them. how you declare them is what's biting you:
#interface MyBaseClass : NSObject
#property (nonatomic, readwrite, retain) NSObject *someObject;
#end
this is the normal way to declare a new objc class.
by adding the parentheses (instead of declaring the superclass - NSObject in this case), you have declared a class extension, which is probably not visible to the subclass (via inclusion).
you will probably never need to declare a root class in objc:
#interface MyBaseClass // << superclass omitted
#property (nonatomic, readwrite, retain) NSObject *someObject;
#end
NSObject (or a subclass of, assuming you're target apple's systems) should be the base class unless you're very experienced and know what a root class is for.
class extensions are often used to 'simulate' private interfaces. by simulate, the compiler doesn't enforce this, as it would be enforced in other languages. for example, all messages are still dynamic, although the subclass may (unknowingly) override methods in your extensions, if declared with the same selector.
Judging by the () after your base class name, it looks like you are declaring a private interface extension within your class implementation, is this the case? If so the variable will only be accessible from within that class implementation.
Does your MyBaseClass inherits from NSObject directly?
If so, you need to declare the someObject property in your interface file, as in:
#interface MyBaseClass : NSObject
{
}
#property (nonatomic, retain) NSObject *someObject;
And then synthesize it like you are already doing.
This is an alternative that meets most of the objectives.
In your header, define the interface
#interface MyBaseClass : NSObject {
NSObject *inheritableObject;
}
#property (readonly) NSObject *inheritableObject;
Now you can edit the inheritableObject in MyBaseClass as well as in any Class that inherits from MyBaseClass. However, from the outside, it is readonly. Not private as in the case of #interface MyBaseClass(), but protected from uncontrolled changes.
super.someObject = nil;. Inheritance means MyBaseClass is your super class.

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.