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.
Related
I'm defining an Objective-C class:
#interface MyRequest : NSObject
#property (strong, nonatomic, readonly) NSDecimalNumber *myNumber;
#property (strong, nonatomic, readonly) CommConfig *commConfig;
#property (nonatomic, assign, readonly) BOOL debug;
How do I make commConfig a static variable? When I use the 'class' keyword, the compiler gives me the following warning:
Class property 'commConfig' requires method 'commConfig' to be defined - use #dynamic or provide a method implementation in this class implementation
And the constructor doesn't recognize this line anymore:
_commConfig = commConfig
If not implemented by the programmer instance properties are automatically implemented by the compiler - an instance variable allocated and getter and/or setter methods written. Class properties are never automatically implemented, you therefore need to declare the static backing variable and define the getter. In your #implementation add:
static CommConfig *_commConfig;
+ (CommConfig *) commConfig { return _commConfig; }
You can call the backing anything you wish, e.g. to follow a naming convention for global/static variables.
HTH
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
I have got a header file (.h) and I want to declare name but all these ways work the same I think because I haven't seen any difference with functionality. Could you tell me what the difference is between:
This with both declarations:
#interface someClass : UIViewController
{
NSString *name;
}
#property (nonatomic, copy) NSString *name;
#end
Without variable:
#interface someClass : UIViewController
{
}
#property (nonatomic, copy) NSString *name;
#end
Or Without property:
#interface someClass : UIViewController
{
NSString *name;
}
#end
#interface someClass : UIViewController
{
NSString *name;
}
#property (nonatomic, copy) NSString *name;
#end
Doing this you will explicitly declare both a property and an ivar.
A property is just a set of methods:
- (void)setName:(NSString*)name;
- (NSString*)name;
An ivar is the memory store holding the value that the property methods manage. This allows you to do:
self.name = ... // access through setter method
name = ... // direct access
The advantage of using properties is that they deal with memory management for you. E.g., in your case, the property is of type copy: this means that with the first syntax (self.name = ...) a copy of the object will be done. If not using properties, you would explicitly need to do: name = [originalString copy]; to obtain the same effect.
Other options you can specify for properties (but not ivars) are: strong and weak ownerships.
Furthermore, a property also represents a public interface to access the variable from outside your class.
Using direct access you are on your own as to memory management (if you are not using ARC).
If you are using ARC and don't define properties, you will not be able to control how the memory is managed by specifying the ownership: strong, weak, retain).
#interface someClass : UIViewController
{
}
#property (nonatomic, copy) NSString *name;
#end
Here you only declare the properties; the ivar is "inferred" by the #synthesize directive in your implementation file. This is only possible in Objective C 2.0 and later (previously, the ivar declaration as above was mandatory).
The same considerations as above applies, with a minor nuance: with older versions of LLVM (ObjC compiler) you will not be able to reference directly the auto-synthesized ivar; with current version of LLVM, if you omit the #synthesize directive, then an automatic ivar named after your property would also be declared (in your case it would be _name).
This last paragraph may seem a bit "advanced", or contrived, but you can safely ignore it.
#interface someClass : UIViewController
{
NSString *name;
}
#end
In this case you are only declaring the ivar. No accessor methods. You will need to handle memory management on your own (if not using ARC), futhermore you will not be able to access the variable from outside the class. For that you need accessors.
Hope this helps.
Case 1:
The is the old method, here the #property and variable are not related until you #synthesize name = name;
Access methods :
variable : name = #"hello"; //direct access to viariable
setter/getter : self.name = #"hello" // set value to name using setName: selector
With the latest xcode just the property is enough.
Case 2:
the new xcode style. Here the synthesize and variable creation is taken care by the compiler. (so less 2 lines of code and this also helps with memory management)
Access methods :
variable : _name = #"hello"; //direct access to viariable
setter/getter : self.name = #"hello" // set value to name using setName: selector
Case 3:
Here the name is just a variable and it dose not have a setter or a getter.
with out property (or) setter & getter this is as good as a local variable and it cannot be accessed from other objects.
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