You want to add properties to your classes so that you can take advantage of dot notation to access those values, as opposed to using methods on your classes.
Anything addressed via dot notation is a property, which is a shortcut to a method. What does that mean? Well, let’s have a look at an example:
NSObject
*
myObject
=
[[
NSObject
alloc
]
init
];
myObject
.
accessibilityHint
=
@"Some string"
;
You can see that we allocated and initialized an object of type
NSObject
and used dot notation to access a property
called accessibilityHint
in that
object. Where did accessibilityHint
come from?
It’s quite simple. A property is defined using the @property
keyword. In fact, if you hold down
the Command key on your keyboard in Xcode, and simply click on the
accessibilityHint
property in the
example that we just saw, you will be redirected to the NSObject.h file where you will see
this:
@property
(
nonatomic
,
copy
)
NSString
*
accessibilityHint
;
But what is a property? It is a high-level language feature—a shortcut, if you will—that allows developers to easily access getters and setter methods on instances of a class without having to refer to the getter and/or the setter method at all. If you want to set a property’s value, you simply use the equals sign to do so. If you want to read from the property, you simply point to it using dot notation.
Let’s look at this in detail. In Recipe 1.12, we saw how we create classes. We
created a class called Person
. Then
in Recipe 1.13, we learned how
to add methods to our classes. Now, by combining the concepts explored
in these two recipes, we can learn more about properties. To start,
let’s go to the Person.h file and
define a property called firstName
:
#import <Foundation/Foundation.h>
@interface
Person
:NSObject
@property
(
nonatomic
,
strong
)
NSString
*
firstName
;
@end
Note
You will learn all about new Automatic Reference Counting
keywords, such as strong
, in Recipe 1.17.
A nonatomic
property is a
property that is not meant to be accessed and changed by multiple
threads at the same time. Such a property or variable is not
thread-safe. A thread-safe (atomic) variable will prevent multiple
threads from writing to it at the same time, or a thread from reading it
while another thread is writing to it. For performance reasons (as well
as the overhead necessary for handling such variables), atomic
properties are not by default provided in iOS by the runtime. Only apps
developed for the Mac can take advantage of both atomic and nonatomic
properties. If you want your properties to be atomic, you will need to
handle threading and access on your own using locks or other mechanisms
that are outside the scope of this book.
In terms of the setter and the getter methods, fortunately, we don’t have to
write these two methods for properties manually. The LLVM compiler
automatically generates these setter and getter methods by putting a
hidden @synthesize
in the
implementation of our object. This keyword simply creates a getter and a
setter method for that property. For instance, if you simply create a
property named firstName
, the
compiler will take the following actions on your behalf:
Creates an instance method for you named
_firstName
. This rule applies similarly to any other property name.Triggers the following synthesize for you in your implementation file without you having to touch it:
@synthesize
firstName
=
_firstName
Under Automatic Reference Counting, it also takes care of deallocating your properties for you.
Now we can go ahead and use our Person
class. Here is an example:
#import "SomeOtherClass.h"
#import "Person.h"
@implementation
SomeOtherClass
-
(
void
)
makeNewPerson
{
Person
*
newPerson
=
[[
Person
alloc
]
init
];
newPerson
.
firstName
=
@"Andrew"
;
NSLog
(
@"First name = %@"
,
newPerson
.
firstName
);
NSLog
(
@"First name = %@"
,
[
newPerson
firstName
]);
}
@end
The example code prints the first name of newPerson
twice, first using its firstName
property and then by calling the
firstName
getter
method on that object. Both will point to the same method,
which @synthesize
created for us in
the Person.m file.
Note
In an older version of the Objective-C runtime, for @property
to work, we also had to define an
instance variable. An instance variable is a
variable whose memory management is done by the programmer herself.
Instance variables are also not exposed to classes outside the scope
of the class that defines them (i.e., they are not exposed to any
class that simply imports the class with the instance variable).
Instance variables are normally called ivars by
professional Objective-C developers (ivar is pronounced I-WAR).
With the new runtime, we don’t have to define ivars anymore. We simply define the property and the LLVM compiler defines the ivar for us. If you are using the GCC compiler, which is rather unlikely, you will see big differences from how the LLVM compiler treats ivars. For instance, in GCC 4.2, an ivar is not accessible to any subclass of a class, whereas if you are using LLVM Compiler, a subclass of a class can use its superclass’s ivars. So make sure you are using Apple’s latest compiler, which is LLVM. If a property is read-only, the only way that property’s value can change is for the class that defines that property to use the ivar of that property to change the property’s value.
If you want to fiddle around with setter and getter methods, you
are free to do so. Even if you have used @synthesize
to allow the compiler to generate
the setter and getter methods of a property for you, you can still go
ahead and override those methods. For instance, in this example, I
change the setFirstName:
setter
method of the firstName
property of
the Person
:
#import "Person.h"
@implementation
Person
-
(
void
)
setFirstName:
(
NSString
*
)
paramFirstName
{
_firstName
=
[
paramFirstName
stringByAppendingString:
@" Jr"
];
}
-
(
id
)
init
{
self
=
[
super
init
];
if
(
self
)
{
// Initialization code here.
_lastName
=
@"Carnegie"
;
}
return
self
;
}
@end
I have overridden the setter method of my firstName
property to add a “ Jr” suffix to
any string that I am told to assign to the firstName
property. So when the setter and
getters are invoked, as before:
Person
*
newPerson
=
[[
Person
alloc
]
init
];
newPerson
.
firstName
=
@"Andrew"
;
NSLog
(
@"First name = %@"
,
newPerson
.
firstName
);
NSLog
(
@"First name = %@"
,
[
newPerson
firstName
]);
NSLog
(
@"Last name = %@"
,
newPerson
.
lastName
);
We will get the following printed out to the console window:
First name = Andrew Jr First name = Andrew Jr Last name = Carnegie
If you want to define a read-only property, all you have to do is
to define your property using the @readonly
keyword, like so:
@property
(
nonatomic
,
strong
,
readonly
)
NSString
*
lastName
;
Get iOS 6 Programming Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.