What is @property in iOS mean?

By | November 19, 2014

The goal of @property directive in iOS is to create the getters and setters for that object so that you can access it in your program. It allows you to specify the behavior of a public property on a semantic level, and it takes care of the implementation details for you.

This article also tells how you can alter these “getters and setters” that are generated by @property

The @property Directive

Let’s see what happens when we declare an @property directive.

Lets study it with an example

 // Car.h
#import <Foundation/Foundation.h>

@interface Car : NSObject

@property BOOL running;

@end
// Car.m
#import "Car.h"

@implementation Car

@synthesize running = _running;    // Optional for Xcode 4.4+

@end

The compiler generates a getter and a setter for the “running” property.
The default naming convention is to use the property itself as the getter, prefix it with set for the setter, and prefix it with an underscore for the instance variable, like so:

- (BOOL)running {
    return _running;
}
- (void)setRunning:(BOOL)newValue {
    _running = newValue;
}

So when you declare a variable using @property this means that you can call its getter and setter as if it is included in the class interface.

You can also override them in Car.m to supply custom getter/setters, but this makes the @synthesize directive mandatory.
However, you should rarely need custom accessors, since @property attributes let you do this on an abstract level.

so when you call

Car *maruti = [Car new];
maruti.running = YES;                // [maruti setRunning:YES]
NSLog(@"%d", maruti.running);        // [maruti running]

You can also change the default getter and setter like this.


@property (getter=isRunning) BOOL running;

Now the “getter” method is called “isRunning” and “setter” method is “setRunning”


Car *maruti = [[Car alloc] init];
maruti.running = YES;                // [maruti setRunning:YES]
NSLog(@"%d", maruti.running);        // [maruti isRunning]
NSLog(@"%d", [maruti running]);      // Error: method no longer exists

The readonly Attribute

When you specify “readonly” attribute to a variable, compiler omits its its setter method but the “getter” is unaffected.


#import <Foundation/Foundation.h>

@interface Car : NSObject

@property (getter=isRunning, readonly) BOOL running;

- (void)startEngine;
- (void)stopEngine;

@end


// Car.m
#import "Car.h"

@implementation Car

- (void)startEngine {
    _running = YES;
}
- (void)stopEngine {
    _running = NO;
}

@end

@property also generates an instance variable for us, which is why we can access _running without declaring it anywhere (we can’t use self.running here because the property is read-only).


Car *maruti = [Car new];
[maruti startEngine];
NSLog(@"Running: %d", maruti.running);
maruti.running = NO;                      // Error: read-only property

The nonatomic Attribute

Atomicity deals with how properties behave in a threaded environment.
When you have more than one thread, it’s possible for the setter and the getter to be called at the same time.
This means that the getter/setter can be interrupted by another operation, possibly resulting in corrupted data.

Using atomic somewhat means that your variable is thread safe.

Properties declared with @property are atomic by default, and this does incur some overhead.

So if we can do like this if you application is not a multithreaded application


@property (nonatomic) NSString *model;

The strong Attribute

The strong attribute creates an owning relationship to whatever object is assigned to the property. This is the implicit behavior for all object properties, which is a safe default because it makes sure the value exists as long as it’s assigned to the property.

Let’s take a look at how this works by creating another class called Person. It’s interface just declares a name property:


// Person.h
#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic) NSString *name;

@end


// Person.m
#import "Person.h"

@implementation Person

- (NSString *)description {
    return self.name;
}

@end

Above implementation overrides NSObject’s description method, which returns the string representation of the object.

Now we will add a person to the Car Class


// Car.h
#import <Foundation/Foundation.h>
#import "Person.h"

@interface Car : NSObject

@property (nonatomic) NSString *model;
@property (nonatomic, strong) Person *driver;

@end

Now during usage


Person *hari = [Person new];
hari.name = @"hari";

Car *maruti = [Car new];
maruti.model = @"Maruti Swift";
maruti.driver = hari;

NSLog(@"%@ is driving the %@", maruti.driver, maruti.model);
        

Since driver is a strong relationship, the maruti object takes ownership of john.
This ensures that it will be valid as long as maruti needs it.

The weak Attribute

Strong references pose a problem if, for example, we need a reference from driver back to the Car object he’s driving. First, let’s add a car property to Person.h:


// Person.h
#import <Foundation/Foundation.h>

@class Car;

@interface Person : NSObject

@property (nonatomic) NSString *name;
@property (nonatomic, strong) Car *car;

@end

The @class Car line is a forward declaration of the Car class. It’s like telling the compiler, “The Car class exists, don’t try to find it right now.”

Now use it like this


maruti.driver = hari;
hari.car = maruti;       // Add this line

Now there is a relation b/w maruti and Person and also Person and maruti.
So it is not destroyable by memory management.

This is called a retain cycle, which is a form of memory leak.

But we can fix it by using “weak” attribute like this


@property (nonatomic, weak) Car *car;

The weak attribute creates a non-owning relationship to car.
This allows hari to have a reference to maruti while avoiding a retain cycle.

The copy Attribute

The copy attribute is an alternative to strong. Instead of taking ownership of the existing object, it creates a copy of whatever you assign to the property, then takes ownership of that. Only objects that conform to the NSCopying protocol can use this attribute.

Example


// Car.h
@property (nonatomic, copy) NSString *model;

Now, Car will store a brand new instance of whatever value we assign to model.


Car *maruti = [Car new];
NSMutableString *model = [NSMutableString stringWithString:@"Maruti Swift"];
maruti.model = model;

NSLog(@"%@", maruti.model);
[model setString:@"Maruti Zen"];
NSLog(@"%@", maruti.model);            // Still "Maruti Swift"

The retain Attribute

The retain attribute is the Manual Retain Release version of strong, and it has the exact same effect: claiming ownership of assigned values.
You shouldn’t use this in an Automatic Reference Counted environment.

The assign Attribute

The assign attribute doesn’t perform any kind of memory-management call when assigning a new value to the property.
This is the default behavior for primitive data types, and it used to be a way to implement weak references before iOS 5.
Like retain, you shouldn’t ever need to explicitly use this in modern applications.

Summary

getter= —> Use a custom name for the getter method.
setter= —> Use a custom name for the setter method.
readonly —> Don’t synthesize a setter method, creates only getter method [the trick to make setter method “private” for class users – so only getter method will be visible for compiler. Usually in implementation file this property is redeclared without readonly attribute using custom category so that setter method can be used inside class itself.]
nonatomic —> Don’t guarantee the integrity of accessors in a multi-threaded environment. This is more efficient than the default atomic behavior.
strong —> Create an owning relationship between the property and the assigned value. This is the default for object properties. [synthesized getter method will return ivar directly without locking it for thread-safety]
weak —> Create a non-owning relationship between the property and the assigned value. Use this to prevent retain cycles.
copy —> Create a copy of the assigned value instead of referencing the existing instance.
retain —> Class retains the pointer, the previous value is released

Leave a Reply

Your email address will not be published. Required fields are marked *