Readonly Properties in Objective-C?
Another way I've found to work with readonly properties is to use @synthesize to specify the backing store. For example
@interface MyClass
@property (readonly) int whatever;
@end
Then in the implementation
@implementation MyClass
@synthesize whatever = m_whatever;
@end
Your methods can then set m_whatever
, since it is a member variable.
Another interesting thing I have realized in the past few days is you can make readonly properties that are writable by subclasses like such:
(in the header file)
@interface MyClass
{
@protected
int m_propertyBackingStore;
}
@property (readonly) int myProperty;
@end
Then, in the implementation
@synthesize myProperty = m_propertyBackingStore;
It will use the declaration in the header file, so subclasses can update the value of the property, while retaining its readonlyness.
Slightly regrettably in terms of data hiding and encapsulation though.
Eiko and others gave correct answers.
Here's a simpler way: Directly access the private member variable.
Example
In the header .h file:
@property (strong, nonatomic, readonly) NSString* foo;
In the implementation .m file:
// inside one of my init methods
self->_foo = @"someString"; // Notice the underscore prefix of var name.
That’s it, that’s all you need. No muss, no fuss.
Details
As of Xcode 4.4 and LLVM Compiler 4.0 (New Features in Xcode 4.4), you need not mess with the chores discussed in the other answers:
- The
synthesize
keyword - Declaring a variable
- Re-declaring the property in the implementation .m file.
After declaring a property foo
, you can assume Xcode has added a private member variable named with a prefix of underscore: _foo
.
If the property was declared readwrite
, Xcode generates a getter method named foo
and a setter named setFoo
. These methods are implicitly called when you use the dot notation (my Object.myMethod). If the property was declared readonly
, no setter is generated. That means the backing variable, named with the underscore, is not itself readonly. The readonly
means simply that no setter method was synthesized, and therefore using the dot notation to set a value fails with a compiler error. The dot notation fails because the compiler stops you from calling a method (the setter) that does not exist.
The simplest way around this is to directly access the member variable, named with the underscore. You can do so even without declaring that underscore-named variable! Xcode is inserting that declaration as part of the build/compile process, so your compiled code will indeed have the variable declaration. But you never see that declaration in your original source code file. Not magic, just syntactic sugar.
Using self->
is a way to access a member variable of the object/instance. You may be able to omit that, and just use the var name. But I prefer using the self+arrow because it makes my code self-documenting. When you see the self->_foo
you know without ambiguity that _foo
is a member variable on this instance.
By the way, discussion of pros and cons of property accessors versus direct ivar access is exactly the kind of thoughtful treatment you'll read in Dr. Matt Neuberg's Programming iOS book. I found it very helpful to read and re-read.
You need to tell the compiler that you also want a setter. A common way is to put it in a class extension in the .m file:
@interface YourClass ()
@property (nonatomic, copy) NSString* eventDomain;
@end
See Customizing Existing Classes in the iOS Docs.
readonly Indicates that the property is read-only. If you specify readonly, only a getter method is required in the @implementation. If you use @synthesize in the implementation block, only the getter method is synthesized. Moreover, if you attempt to assign a value using the dot syntax, you get a compiler error.
Readonly properties only have a getter method. You can still set the backing ivar directly within the property's class or using key value coding.