get Property attribute in continuation class does not match the primary class - objective-c

In myClass.h, I do:
typedef enum {
SignUpLabel,
SignUpButton,
LogInFieldsTwitterButton,
LogInFieldsFacebookButton,
LogInWithFaceBookTiwtterLabel,
} logInFields;
#property (nonatomic, readonly, assign) logInFields fields;
#end
I want logInField to be readonly for public, but it can be read/write in private. Therefore, I do this:
#interface myClass ()
#property (readwrite, assign ) logInFields fields;
#end
However, I am getting a warning:
Property attribute in continuation class does not match the primary class
Can somebody tell me what I am missing here and how to silence the compiler?

Did you try adding "nonatomic" in the .m?

Related

"property has a previous declaration" error in class extension: bug or feature?

In Objective-C you can generally re-declare a readonly property as readwrite in a class extension like this:
#interface PubliclyImmutablePrivatelyMutableClass : NSObject
#property (readonly, nonatomic) SomeStateEnum someState;
#end
// In "PubliclyImmutablePrivatelyMutableClass+Private.h"
// or "PubliclyImmutablePrivatelyMutableClass.m"
#interface PubliclyImmutablePrivatelyMutableClass()
#property (readwrite, nonatomic) SomeStateEnum someState;
#end
// In "PubliclyImmutablePrivatelyMutableClass.m"
#implementation PubliclyImmutablePrivatelyMutableClass #end
If, however, I introduce a property in a class extension as readonly and try to re-declare it as readwrite in a second one, Xcode 10’s Clang gives me a compiler error:
#interface ClassWithPrivateImmutableInternallyMutableProperty : NSObject
// any public API
#end
// In "ClassWithPrivateImmutableInternallyMutableProperty+Private.h"
#interface ClassWithPrivateImmutableInternallyMutableProperty()
#property (readonly, nonatomic) SomePrivateStateEnum somePrivateState;
#end
// In "ClassWithPrivateImmutableInternallyMutableProperty.m"
#interface ClassWithPrivateImmutableInternallyMutableProperty()
#property (readwrite, nonatomic) SomePrivateStateEnum somePrivateState; // error: property has a previous declaration
#end
#implementation ClassWithPrivateImmutableInternallyMutableProperty
// other API
#end
Now I wonder:
Is the compiler error a bug/regression in Clang or a deliberate feature?
If it’s a bug, is there another workaround than manually implementing the setter?
I believe that this is correct behavior from the compiler.
In the second example you are using two class continuation categories with the same name () to declare the same property on two occasions. It is effectively the same as declaring the same property name twice in the same extension.
Note that this differs from the first example, in which the property is declared first in the header and then re-declared in a single class continuation category named ().
If I am right, then the answer is to mark the '+private' class extension with a name like (Private) instead of ():
#interface ClassWithPrivateImmutableInternallyMutableProperty(Private)
And also if you have any implementation for the private extension:
#implementation ClassWithPrivateImmutableInternallyMutableProperty(Private)
I hope that helps!

Objective-C NSCoding and Read-only

Objective C Read-only
I want to change my NSCoding property to read-only.
For example, let’s set the readonly attribute for the lastName property on Person:
Person.h
#interface Person : NSObject
#property NSString *firstName;
#property (readonly) NSString *lastName;
#end
Assignment to readonly property
Okay, so outside code can’t set the property value, But when I tagged the lastName property with the readonly attribute by including (readonly) right after the #property declaration. but I still receive an error like this:
Person.m
#import "Person.h"
#implementation Person
- (void) changeLastName:(NSString *)newLastName;
{
self.lastName = newLastName;
}
#end
Assignment to readonly property
What happens here? Can someone tells me why It doesn’t work.
Thanks.
You need to redeclare it inside the class as readwrite
// Person.m
#import "Person.h"
#interface Person()
#property (readwrite) NSString *lastName;
#end
#implementation Person
-(void)changeLastName:(NSString *)newLastName;
{
self.lastName = newLastName;
}
#end
Properties don't distinguish between callers when you're trying to set a property. If you want to set a readonly property from inside its class, use
_lastName = newLastName
in your case to set the ivar directly.
If you want to set a readonly property from inside its class, you can write the following code:
_lastName = newLastName
You need to redeclare it inside the class as readwrite
It's straightforward.
If you want to set a readonly property from inside its class, use
_lastName = newLastName
You need to redeclare it inside the class as readwrite

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.

Difference between #property (nonatomic, readonly) and #property inside class extension?

I have an Objective-c class "MyClass". In MyClass.m I have a class extension that declares a CGFloat property:
#interface MyClass ()
#property (nonatomic) CGFloat myFloat;
#end
#implementation MyClass
#synthesize myFloat;
//...
#end
What changes (if anything) when the property is declared using the readonly keyword?
#interface MyClass ()
#property (nonatomic, readonly) CGFloat myFloat;
#end
#implementation MyClass
#synthesize myFloat;
//...
#end
Perhaps in the first case I can say self.myFloat = 123.0; and CGFloat f = self.myFloat; inside MyClass? Then in the second case the readonly keyword prevents the assignment self.myFloat = 123.0; but allows the read CGFloat f = self.myFloat;
The option readonly means that only the getter method is being declared for this property. Thus, without a setter, it can't be modified via myObject.myFloat=0.5f;
If you don't declare it readonly, it's read write by default.
Declaring your property via () extension does not modify the access mode but it modifies the scope; it will be a "private" property.
#synthesize uses the #property definition to generate the appropiate getter/setter for the iVar. When you specify readonly, no setter is generated. This is not strictly enforced as you can write your own setter if you choose (though that doesn't make a ton of sense).
Declaring the property in a category simply defines the scope of the property to be within that category.
You're right, declaring your property as readonly you tell compiler to not generate setter method automatically and so self.myFloat = 123.0; will be illegal (unless you create that method manually).

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.