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
Related
I have a class MyConfig with a property/ variable NSString * url. By private, I don't want anyone to be able to set the url outside of the MyConfig class. For example, I don't want the following to be allowed:
MyConfig * myConfig = [[MyConfig alloc] init];
myConfig.url = #"some url";// I want to forbid this
My goals:
forbit the setting of the variable/ property via dot notation
use automatically generated/ standard getter (myConfig.url) and setter ([myConfig setUrl]) - I don't want to write the
getters and setters myself
What I have:
MyConfig.h
#interface MyConfig : NSObject
#property (readonly) NSString * url;
#end
Problem: standard getter is not working!
MyConfig * myConfig = [[MyConfig alloc] init];
[myConfig setUrl];// Instance method "-setUrl:" not found (return default type is "id")
This shouldn't be the case according to this right?
Is there a better way to achieve my goal?
You could try creating a public property for your getter such as you have already and then create the private version in your implementation file such as below.
MyConfig.h
// Public interface that the world can see
#interface MyConfig : NSObject
#property (readonly) NSString *url; // Readonly so the getter will be generated but not the setter
#end
MyConfig.m
#import "MyConfig.h"
// Private interface that only your implementation can see
#interface MyConfig() // Class extension
#property (nonatomic, strong) NSString *url; // Private getter and setter
#end
#implentation MyConfig
// The rest of your code...
#end
The way that I have implemented this is using class extensions, the syntax to declare a class extension is the same as the one for creating a category with an empty name. Moreover and quite an important part is that we don't have to define another implementation block, the implementation for this extension and the code in it has to be implemented in the main implementation block.
Using the class extension method (Not possible with categories) we can have a property with a readonly access public facing and readwrite access privately. To do this we declare the property as readonly in your header file and redeclare it as readwrite in your class extension.
The easiest way is to declare this property in your implementation (.m) file:
#interface MyConfig () //This declares a category/extension to your header file
#property (nonatomic, strong) NSString * url; //This property is private
#end
#implementation MyConfig
//Your code
#end
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?
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).
Is there a way to declare a private property in Objective C? The goal is to benefit from synthesized getters and setters implementing a certain memory management scheme, yet not exposed to public.
An attempt to declare a property within a category leads to an error:
#interface MyClass : NSObject {
NSArray *_someArray;
}
...
#end
#interface MyClass (private)
#property (nonatomic, retain) NSArray *someArray;
#end
#implementation MyClass (private)
#synthesize someArray = _someArray;
// ^^^ error here: #synthesize not allowed in a category's implementation
#end
#implementation MyClass
...
#end
I implement my private properties like this.
MyClass.m
#interface MyClass ()
#property (nonatomic, retain) NSArray *someArray;
#end
#implementation MyClass
#synthesize someArray;
...
That's all you need.
A. If you want a completely private variable. Don't give it a property.
B. If you want a readonly variable that is accessible external from the encapsulation of the class, use a combination of the global variable and the property:
//Header
#interface Class{
NSObject *_aProperty
}
#property (nonatomic, readonly) NSObject *aProperty;
// In the implementation
#synthesize aProperty = _aProperty; //Naming convention prefix _ supported 2012 by Apple.
Using the readonly modifier we can now access the property anywhere externally.
Class *c = [[Class alloc]init];
NSObject *obj = c.aProperty; //Readonly
But internally we cannot set aProperty inside the Class:
// In the implementation
self.aProperty = [[NSObject alloc]init]; //Gives Compiler warning. Cannot write to property because of readonly modifier.
//Solution:
_aProperty = [[NSObject alloc]init]; //Bypass property and access the global variable directly
It depends what you mean by "private".
If you just mean "not publicly documented", you can easily enough use a class extension in a private header or in the .m file.
If you mean "others are not able to call it at all", you're out of luck. Anyone can call the method if they know its name, even if it is not publicly documented.
As others have indicated, (currently) there is no way to truly declare a private property in Objetive-C.
One of the things you can do to try and "protect" the properties somehow is to have a base class with the property declared as readonly and in your subclasses you can redeclare the same property as readwrite.
Apple's documentation on redeclared properties can be found here: http://developer.apple.com/library/ios/DOCUMENTATION/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW19
I was trying to create a property which is readonly. I wanted to initialize with a value from the class creating an instance of this class, e.g.
#property (retain,readonly) NSString *firstName;
And I tried to initialize it like this:
-(id)initWithName:(NSString *)n{
self.firstName = n;
}
Once I did this, the compiler reported an error that the readonly property cannot be assigned. So how can i do this ?
Either assign to the instance variable directly (don't forget to add a retain or copy if you need it) or redeclare the property in a private class extension. Like this:
In your .h file:
#property (readonly, copy) NSString *firstName;
In your .m file:
#interface MyClass ()
// Redeclare property as readwrite
#property (readwrite, copy) NSString *firstName;
#end
#implementation MyClass
#synthesize firstName;
...
Now you can use the synthesized setter in your implementation but the class interface still shows the property as readonly. Note that other classes that import your .h file can still call -[MyClass setFirstName:] but they won't know that it exists and will get a compiler warning.
Don't use the synthesized setter:
firstName = [n retain]; //Or copy
It is generally advised to bypass the setters in any init and dealloc methods anyway.
You can directly access the property with:
_firstName = n;
The setter method that self.firstName = n implies will not be synthesized because you specified readonly in #property (retain,readonly) NSString *firstName;, hence the compiler error.