Properties
Properties in objective c are
a convenient way to provide the accessors (getter
and setter) for instance variable in objective - c language. Let suppose you
have a mobile then what are its properties?
Name:
Brand Name:
Screen Size:
etc.
So properties define the things. In a similar
manner properties in objective - c define the class or objects.
A Simple Example for a Person class with the basic
attribute.
Example:
@interface Person : NSObject
@property NSString* name;
@end
Compiler will generate
a getter and setter for you
with the following convention:
- (void) setName:(NSString*)name{
//Compiler generated the code for getter property
}
- (NSString*)name{
//Compiler generated the code for getter property
}
From the above code there are some questions raised
in mind?
1) What is the name of instance variable in the
above case?
2) How is the memory management will happen for the
instance variable?
We go one by one first let us know the name of
instance variable in above case:
Binding Instance variable with Properties:
Let suppose you declare the property name as given below:
@interface Person : NSObject
@property NSString* name;
@end
There are three ways to bind the instance variable
with the above properties:
1) Declare and Manually Synthesis a
Instance Variable
Person.h
@interface Person : NSObject{
NSString* _name;
}
@property NSString* name;
@end
Person.m
@implementation Person
@synthesize name = _name;
@end
In above case we specify that the
instance variable "_name" to be bind with the property
"name". Similarly we can specify any other name for the property.
Note: If property and instance name is
same like "name" then we can specify the following in case of
synthesis.
@implementation Person
@synthesize name;
@end
Done :).
Above Xcode 4.4
version it has capability to auto synthesis the properties. You just need to
declare the property name as explain above. Compiler will automatically create
an instance variable matching with the property and synthesis it.
It simulates the following thing for you:
@synthesize name = _name;
Your instance variable will be the same name of the
property with a prefix "_" underscore. You do not need to write
synthesize in this case and no need to declare the variable. Just declare the
property and can directly use the instance variable in init method like following:
Person.h
@interface Person : NSObject
@property NSString* name;
@end
Person.m
@implementation Person
- (instancetype) init{
self = [super init];
_name = [[NSString alloc] initWithFormat:@"property"];
return self;
}
@end
Done :).
3) Dynamic or Manual Setter and Getter
Dynamic behavior is most tough
one for developer ;). In this we need to implement accessors method. So you
need to handle memory management code for the instance variable.
Person.h
@interface Person : NSObject{
NSString* _name;
}
@property NSString* name;
@end
Person.m
@implementation Person
@dynamic name;
- (NSString*) name{
return _name;
}
- (void) setName:(NSString *)name{
//Write Code for store the value in _name and it should be according to memory management.
//Explain later
}
@end
That is all about binding the instance variable
with the properties. Now let move to memory management.
Memory Management With Properties:
Memory handling of instance variable when used
through properties are depend upon object lifetime qualifiers:
1) Strong
2) Retain
3) Copy
4) Assign
5) Weak
Strong:
This qualifier is used to take ownership of the
object. In Strong it only shallow copy the object. So pointers referencing to
the same memory address.
Person.h
@interface Person : NSObject{
NSString* _name;
}
@property (strong) NSString* name;
@end
RootViewController.m
@implementation RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSString* myName = [[NSString alloc] initWithFormat:@"Test"];
[_testPerson setName:myName];
}
@end
In MMR Environment it is your responsibility
to send the release message in both the cases. In person class dealloc method
and in root view controller in the end of view did load method.
In ARC Environment Complier will automatically
place the release call for you in both the cases. So main point is both object
is owner of test string. So both need to release that.
Retain:
Retain is identical to strong. There is no such
difference between retain and strong. Apple introduced a new qualifier with ARC
that is Strong. But it has no difference from retain.
Strong and Retain:
In this case both objects person and root view
controller share the same memory reference. So it is like a two person watching
the same thing.
Copy:
Copy
qualifier is also used to take ownership of object. It has some differences
from the strong or retain. In some case it provided you deep copy except
Collection classes. Both the object has own copy of string object in above case.
@interface Person : NSObject{
NSString* _name;
}
@property (copy) NSString* name;
@end
RootViewController.m
@implementation RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSString* myName = [[NSString alloc] initWithFormat:@"Test"];
[_testPerson setName:myName];
}
@end
It is like two persons watching the different
things but belong to same domain (Different object of same type).
Note: In case of collection class
this will be not deep copy as the elements in the collection shared by both the
owner. If you need to apply this on your custom class then you need to adopt
NSCopying protocol. Based on the implementation by you it will be deep or
shallow copy.
Weak:
Weak qualifier does not claim ownership of object.
So a weak reference remains until there is any strong reference to that object.
So once all the strong reference is vanished the weak reference automatically
becomes the nil.
@interface Person : NSObject{
NSString* _name;
}
@property (weak) NSString* name;
@end
RootViewController.m
@implementation RootViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSString* myName = [[NSString alloc] initWithFormat:@"Test"];
[_testPerson setName:myName];
}
@end
In ARC once the view did load method of root view
controller is executed then the name in person class will be nil.
Assign:
It is similar to weak but there is subtle
difference between the both. In case of assign when all the strong reference
vanished the reference will not be nil. It will still point to the same memory
address. So it will point to a garbage value. Your Test engineer come to you
with random crash ;).
Undefined Behaviour:
Assign is recommended only for primitive data type
like int, float etc. Do not use it with objects.
This post covered about lifetime qualifier for
properties. This Post will be continue and we will see other qualifier like
atomic, Non atomic with examples.
Comments
Post a Comment