Properties are a feature in Objective-C that allows
us to automatically generate accessors. In this blog I will illustrate what
different attributes in @property (params) will interpolate
. In property we have four kinds
of attributes.
1. Writability
2. Setter Semantics
3. Atomicity
4. Accessor Method Names
You can use all them or none of them. e.g.
@property([Atomicity],[Writability],[Setter Semantics],[Accessor Method Names]) type var_name;
Where [ ] denotes that they are optional.
Note:
1. You can only use one attribute from each
category except Accessor Method Names. You can use both in this case.
2. If use readonly(writability) with
setter(accessor method name), it will generate warning.
Writability
In this category we have two attributes
a. readwrite
b. readonly
readwrite
Indicates that the property should be treated as
read/write. This attribute is the default.
e.g.
@interface Person : NSObject {
int age;
float salary;
}
@property int age; // by default attributes are
readwrite, assign and atomic
@property (readwrite) float salary; //This is also same as above
@end
@implementation Person
@synthesize age;
@synthesize salary;
@end
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
Person *objPerson = [[Person alloc] init];
objPerson.age
= 25; //setting the value
NSLog(@"Person
age is %d years",objPerson.age);
//getting the
value
[objPerson setAge:12]; //This is also valid as
copiler will create setter and getter for this property
NSLog(@"Person
age is %d years",[objPerson age]);
//
accessing the
getter method
objPerson.salary = 50000.0f; //setting the value
NSLog(@"Person
salary is %f years",objPerson.salary); //getting
the value
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
[pool release];
return 0;
}
The
compiler will create a setter and getter for
the properties age and salary. By default
the getter method is named same as propertyName and setter is setPropertyName:,
in above example you the
compiler will create accessors like this
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Compilers generated
accessors ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
- (void)setAge:(int)pAge{
age = pAge;
}
- (int)age{
return age;
}
- (void)setSalary:(float)pSalary{
salary = pSalary;
}
- (float)salary{
return salary;
}
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Compilers generated
accessors ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
readonly
This indicates that the property is read-only.
@interface Person : NSObject {
int age;
float salary;
}
@property(readonly) int age;
@end
@implementation Person
@synthesize age;
@end
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
Person *objPerson = [[Person alloc] init];
objPerson.age = 25; //setting
the value will generate error
NSLog(@"Person
age is %d years",objPerson.age);
//accessing
the
getter method
NSLog(@"Person
age is %d years",[objPerson age]);
//
accessing the
getter method
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
[pool release];
return 0;
}
Setter Semantics
These
attributes
specify the semantics of a
set accessor.1.copy
2.assign
3.retain
4.strong
5.weak
copy
Specifies
that a copy
of the object should be
used for assignment. The previous value is sent a release message. The copy is made by invoking the copy method. This attribute is valid only for object types, which must implement the NSCopying protocol.
e.g
I'm taking NSMutableData ivar as this class implements NSCopying protocol.
@interface Person : NSObject {
NSMutableData *objCopy;
}
@property(copy) NSMutableData *objCopy;
@end
@implementation Person
@synthesize objCopy;
@end
int main(int argc, char *argv[])
{
@autoreleasepool {
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
Person *objPerson = [[Person alloc] init];
NSMutableData *tObj = [[NSMutableData alloc] init];
objPerson.objCopy = tObj;
NSLog(@"Instance
variable
%p != temporary object %p",objPerson.objCopy,tObj);
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
}
return 0;
}
Log: Instance variable 0x6830bd0 != temporary object 0x682ced0
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ The compiler generated
setter may
look like this ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
- (void)setObjCopy:(NSObject*)tObj{
if (objCopy != tObj) {
[objCopy release];
objCopy = [tObj copy];
}
}
Note:
I haven't included getter definition here, I will give the
definition
of setter when Atomicity category comes.
assign
Specifies
that the
setter
uses simple assignment. This attribute is the default. @property(assign) type ivar_name;
@property type ivar_name;
Both
are same for example you can refer to first
example.
retain
Specifies
that retain
should be
invoked on the object upon assignment.The previous value is sent a release message and new value is retained.
@property(retain) int abc; //This will generate error
@property(retain) NSObject *obj; //Ok
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ The compiler generated
setter will
look like this ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
- (void)setObj:(NSObject*)tObj{
if (obj != tObj) {
[obj
release];
obj = [tObj retain];
}
}
strong
Specifies
that there
is a
strong (owning) relationship to the destination object. This was
introduced
with the ARC and is similar to retain in non-ARC environment.
weak
Specifies
that there
is a weak
(non-owning) relationship to the destination object.If the destination object is deallocated, the property value is automatically set to nil.
e.g.
I have created a strong and a week reference and after the block is over the strong reference is retained and the week one is released and assigned nil.
@interface Person : NSObject {
NSObject *objStrong;
__weak NSObject *objWeek;
}
@property(strong) NSObject *objStrong;
@property(weak) NSObject *objWeak;
@end
@implementation Person
@synthesize objStrong;
@synthesize objWeak;
@end
int main(int argc, char *argv[])
{
@autoreleasepool {
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
Person *objPerson = [[Person alloc] init];
{
objPerson.objStrong = [[NSObject alloc] init];
objPerson.objWeak = [[NSObject alloc] init];
}
NSLog(@"Strong
is %@",objPerson.objStrong);
NSLog(@"Weak
is %@",objPerson.objWeak);
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
}
return 0;
}
After
the block is
over the week object is deallocated and objWeek reference is
assigned nil;
Here it the log
Strong is <NSObject: 0x68189f0>
Weak is (null)
Atomicity
You
can use this attribute to specify that accessor methods are
not atomic. There is no keyword to denote atomic.
nonatomic
Specifies
that
accessors are nonatomic. By default, accessors are atomic.
Properties
are atomic by default so that synthesized accessors
provide robust access to properties in a multithreaded
environment, that is, the
value returned from the getter or set via the setter is
always fully retrieved
or set regardless of what other threads are executing
concurrently.
If you specify strong, copy, or retain and do not specify nonatomic,
then in a reference-counted environment, a synthesized get
accessor for an object property uses a lock and retains and
autoreleases the
returned value. The implementation of accessors will be
similar to the following:
@property(retain) NSObject *obj;
- (void)setObj:(NSObject*)tObj{
[_internal lock]; // lock using an object-level lock
if (obj != tObj) {
[obj
release];
obj = [tObj retain];
}
[_internal unlock];
}
- (NSObject*)obj{
[_internal lock]; // lock using an object-level lock
id result = [[ obj
retain] autorelease];
[_internal unlock];
return result;
}
And if you write nonatomic then accessors will be similar to the following:
@property(retain) NSObject *obj;
- (void)setObj:(NSObject*)tOb{
if
(obj != tObj) {
[obj
release];
obj = [tObj retain];
}
}
- (NSObject*)obj{
return obj;
}
Accessor
Method Names
The
default names for the getter and setter methods associated
with a property are propertyName and setPropertyName:
respectively for example, given a property foo,
the accessors would be foo and setFoo:.
The following attributes allow you to specify
custom names instead. They are both optional and can appear
with any other
attribute (except for readonly in the case of setter=).
getter=getterName
Specifies
the name of
the get accessor for the property. The getter must return a
type matching the
property's type and take no parameters.
setter=setterName
Specifies
the name of
the set accessor for the property. The setter method must
take a single
parameter of a type matching the property's type and must
return void.If you specify that a property is readonly and also specify a setter with setter=, you get a compiler warning.
@interface Person : NSObject {
NSObject *obj;
}
@property(getter = myGetter, setter = setMySetter:) NSObject *obj; //Ok
@end
@implementation Person
@synthesize obj;
@end
int main(int argc, char *argv[])
{
@autoreleasepool {
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
Person *objPerson = [[Person alloc] init];
NSObject *tObj = [[NSObject alloc] init];
objPerson.mySetter = tObj;
NSLog(@"Object
reference %p",objPerson.myGetter);
/*
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
}
return 0;
}
Property Implementation Directives
1. @synthesize
2. @dynamic
@synthesize
You use the @synthesize
directive to tell the compiler
that it should synthesize the setter and/or
getter methods for a property if
you do not supply them within the @implementation block. The @synthesize
directive also synthesizes an
appropriate instance variable if it is not
otherwise declared.You can use the form property=ivar to indicate that a particular instance variable should be used for the property, for example:
@interface Person : NSObject {
NSObject *obj;
}
@property(nonatomic, retain) NSObject *obj; //Ok
@end
@implementation Person
@synthesize obj = myObj;
- (void)aMehtod{
obj = nil;
myObj = nil; //both will work
}
@end
@dynamic
You use the @dynamic
keyword to tell the compiler
that you are going to provide fulfill the API
contract implied by a property
either by providing method implementations
directly or at runtime using other
mechanisms such as dynamic loading of code or
dynamic method resolution. It
suppresses the warnings that the compiler
would otherwise generate if it can't
find suitable implementations. You should use
it only if you know that the
methods will be available at runtime.e.g.
@interface Person : NSObject {
NSObject *obj;
}
@property(nonatomic, retain) NSObject *obj; //Ok
@end
@implementation Person
@dynamic obj;
- (void)setObj:(NSObject*)tObj{
if (obj != tObj) {
[obj
release];
obj = [tObj retain];
}
}
- (NSObject*)obj{
return obj;
}
@end
Here
you have provided the implementation at
compile time
If
you have ever used core data then the managed
class will look like
@interface MyClass : NSManagedObject
@property(nonatomic, retain) NSString *value;
@end
@implementation MyClass
@dynamic value;
@end
And in this case the definitions are provided at
runtime.