Download as pdf or txt
Download as pdf or txt
You are on page 1of 16

Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

Details
Created on Saturday, 09 July 2011 10:18

Anyone who wants to develop programs for the products of Apple Company meets such a moment in his life
when he needs to learn new programming language - Objective-C. I met such moment once too. I decided to
take notes of my thoughts when understanding the documentation to remember the main specifics of this
language.

Banal Theory of Origin of OOP

The problem of reuse of the written code and its portability always makes the developers search for new ways of
its sorting, organization, and abstracting. New programming paradigms, design patterns, languages, compilers and
standard libraries for them, program platforms and frameworks are created to solve these problems. In such a
way, a paradigm of subprograms (procedures) appeared. It is implemented with the help of CALL\RET processor
commands and stack (in fact, it is redirection of the execution thread by the address of an arbitrary command but
not the one following the current command, with the subsequent return). Then, there is a paradigm of modules
(each file is a separate translation unit) that created a two-stage translation: compilation of modules and then
their linking (static and dynamic) to an executable module. As a result of increasing of the code size in projects
and difficulties of its support, a new object – oriented paradigm of programming appeared in early 1960s. This
paradigm splits programs into even smallest components – types of data. Its main point consists in interaction of
entities (objects) by means of sending messages to each other. Each object is a variable of a data type defined by
the developer (the so-called class). The definition of such special user data type (class) consists in the following
two things: definition of data set (invariants, members) and a set of subprograms (methods) that will serve them.

Class is usually designed as a type defined by the developer. This type is based on embedded (language) data
types and/or other classes. This can be a structure (struct) for the C language that does not support an object-
oriented paradigm. A set of subprograms is implemented as usual functions that have at least one parameter –
pointer to a data set that is to be handled. The main advantage of the object-oriented method is the possibility to
create new classes on the basis of the written ones (to add invariants and methods, redefine methods, use
methods defined in the base class as their own). It is called inheritance.

1 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

A set of methods represents an interface for interaction with invariants. Impossibility of direct modification of
class data (without using its interface) reflects the principle of encapsulation. On the figure above, class and its
oblects are represented. There is an x invariant of float type and doubleX interface (method) for it that returns
the invariant value. Sometimes it is necessary to send message to an object that responds to it definitely (i.e., to
call the method implemented for this class object), but the certain class of this object is unknown according to
cicumstances. For example, we need to send a Move message to each element of the list of pointers to objects of
Auto class. And we know that there are pointers to objects of not only Auto class in the list but there are also
pointers to derivative (inherited) Ford and Subaru classes. We can do it only due to the polymorphism principle.
It consists in the following: when a certain message is sent to an object from a certain class hierarchy, where all
objects can receive such message, this object responds to it correspondingly to its own class but not the basic
class for the current hierarchy. Simula 67 became the first language with the support of the object-oriented
approach. Then, Smalltalk appeared. And in 1980s, C++ appeared, the main language of the modern system
programming. Its expansion and improvement in 1990s generated a number of design paradigms and patterns. It
also influenced the modern vision of object-oriented approach, including Objective-C language.

A Little of History

Objective-C appeared in 1980s as a modification of C in Smalltalk “style”. This modification consisted in adding
the new syntactic constructions and in a special preprocessor for them (which transformed them into the simple
calls of C functions in the code), and also in the runtime library (to process those calls). Thus, Objective-C was
initially interpreted as an add-on over C. In some way, it is still so: we can write a program in pure C and then
add some constructions from Objective-C (if necessary). Or vice versa: we can freely use C in programs in
Objective-C. Besides, all of this also concerns programs in C++. In 1988, NeXT (later, Apple) licensed
Objective-C and wrote a compiler and a standard library (SDK in fact) for it. In 1992, the developers of the GNU
project within the OpenStep project improved of the language and compiler. Since then, GCC has supported
Objective-C. After buying NeXT, Apple took their SDK (compiler, libraries, IDE) as a basis for their further
implementations. IDE for the code was named Xcode and IDE for GUI was named Interface Builder. Cocoa
framework for GUI implementations (and not only for them) is the most significant development environment for
programs in Objective-C nowadays.

Specifics of Objective-C
Module files in Objective-C have the “.m” extension (if the mix of C++ and Objective-C was used, then the
extension is “.mm”). Header files have the “.h” extension. All class objects created in Objective-C must be
allocated in the dynamic memory. That is why, id type takes special significance. This type is a pointer to an
object of any class (void * in fact). The zero pointer is named by the nil constant. Thus, we can convert the
pointer to any class to the id type. A problem appears: how can we know to which class the object that is hidden
behind id refers? It is made using the isa invariant that is present in any class object that inherited the special
NSObject basic class (NS prefix means NeXT Step). The isa invariant refers to the reserved Class type. The
object of such type allows to find out names of its own and basic class, set of class invariants, and also

2 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

prototypes of all methods that this object implements and their addresses (by means of the local list of selectors).
All reserved Objective-C words that differ from the reserved C language words start with the @ symbol (for
example, @protocol, @selector, @interface). Usually, names of class invaiants with the limited scope
(@private, @protected) start with the underscore character. There is a convenient NSString class for strings in
Cocoa. String constant of such class is written as @”Hello world” and not as a simple C string constant “Hello
world”. The BOOL type (in fact, unsigned char) can accept YES and NO constant values. All reserved words
specific for Objective-C (that differ from C language and are located in the objc/objc.h header file) are listed
below:

@interface – Starts the declaration of the class or category (category is an extension of the class by
additional methods without inheritance)
@implementation – Starts the definition of the class or category
@protocol – Starts the declaration of a protocol (analog of C++ class that consists of only virtual
functions)
@end – Ends the declaration\definition of any class, category, or protocol
@private – Limits the scope of visibility of class invariants for the class methods (similarly to C++)
@protected – is set by default. Limits the scope of visibility of class invariants for the class methods and
methods of derivative classes (similarly to C++)
@public – Deletes the limitations for the scope of visibility (similarly to C++)
@try – Defines the block with a possible generation of exceptions (similarly to C++)
@throw – Generates an object-exception (similarly to C++)
@catch () – Handles the exception generated in the previous @try block (similarly to C++)
@finally – Defines the block after the @try block, to which the control is passed, regardless of the fact if
the exeption was generated or not
@class – Shortened form of class declaration (only the name; similarly to C++)
@selector(method_name) – Returns the compiled selector for the name of the method_name method
@protocol(protocol_name) – Returns the copy of the class-protocol with the protocol_name name
@encode(type_spec) – Initializes the string of symbols that will be used for encryption of data of
type_spec type
@synchronized() – Defines the code block that is executed only by one thread at any certain moment

Message Exchnage

To make the object execute a certain method, we need to send it a message with the same name as the required
method. Such message is called method selector. Sending syntax is as follows:
[receiver method];

We can send parameters for the called method in the message:


[receiver method: 20.0 : 30.0];

We need to put a colon before each parameter. There are as many colons as parameters. The name of the method
can continue after each such colon-parameter:
[receiver methodWithFirstArgument: 10 andSecondArgument: 20];

3 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

Methods with unlimited amount of arguments are called by the following syntax:
[receiver undefinedNumberParameters: one, two, three, four, five, six, seven];

Message sending (as any C function) returns a certain value (perhaps, void):
BOOL booleanValue; booleanValue = [reveiver method];

It disappears when sending the nil message. An exception appears when sending a message to an object that
belongs to a class that did not implement the required method. This exception, being not intercepted, leads the
whole program to an unexpected shutdown. We can use the following code pattern to check if the current object
responds to any message:

1 if  ([anObject respondsToSelector: @selector(myMethodWith2Argumets::)])
2 { //we can  call
3 [anObject  myMethodWith2Argumetns: @”first” : @”second”];
4 }
5 else
6 {
7 //do not  call in any case
8 }

The Work of Message Transfer

Sending a message is translated into the C-function with a prototype:


id objc_msgSend(id receiver, SEL method, …);

The SEL type is defined as char const * in fact. But it is better to interpret it as int because all selectors are
indexed by integer values according to the global table of selectors during the execution.

Using the isa invariant of the receiver object (the presence of isa is inevitable because all classes must inherit
the NSObject class when using Foundation framework, basic for Cocoa), this function browses the local list of
class selectors to define if an object of the current class responds to the method message. If there is such
selector, the control is passed to the corresponding class method. The object id (pointer to its invariants) and
parameters of the objc_msgSend() function defined after the selector are passed to this class method. The value
returned by the method is returned as a result of message sending. If the object-receiver does not have such
selector, the objc_msgSend() function browses the list of selectors of its basic class.

4 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

For example, using such scheme, the call:


[receiver addObject: otherObject];

Is translated into:
objc_msgSend(receiver, 12, otherObject);

In the global table of selectors, 12 corresponds to the “addObject:” string. Next, the objc_msgSend() function
performs the search in the list of selectors of the receiver object. When the function finds it (let it be an object of
the NSArray class, which implemented the method with 12 selector), it performs the call of the type:
addObject(receiver, otherObject);

Method Declaration

It is interesting to note that the prototype of the addObject method from the previous part looked as follows in
the class declaration:
- (void)addObject: (id)otherObject;

It accepted only one parameter. Proceeding from the principle of object-oriented paradigm that methods are
subprograms that handle certain data sets we need to pass address of data to be processed to the method. That is
why such parameter is passed to any class method indirectly. The minus sign (“-“) that stands first in the method
prototype informs the compiler about the additional parameter. Such method (with the minus sign before) is
called the object method (or instance method). It can be called only for the object of any class. In the method
body, this pointer to the copy of data (or the object address to which the message was sent) is available by means
of the reserved self word (similarly to this in C++). The pointer to the instance of the basic class is available
through the reserved super word. Besides, an indirect _cmd parameter – selector of this method from the global
table of selectors – is passed to the object method. From the C++ developer point of view, all object methods in
Objective-C are like those declared with the virtual key word and always follow the dynamic polymorphism. If
we put the plus sign (“+”) in the beginning of the method prototype, such method will be interpreted as class
method and will not accept the indirect self parameter, correspondingly (it is similarly to the declaration of static-
method in C++). The super pointer will not also work without the isa object invariant to which self points.
Thus, the prototype of any method is declared in the following way:
-|+ (<type of the returned value>) main PartoftheMethodName [ : (<type of the first para

5 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

For example:
+ (Class)class;
+ (id)alloc;
- (id)init;
- (void)addObject: (id)anObject;
+ (NSString *)stringWithCString: (const char*)aCString usingUncoding: (enum NSStringEncoding
- (NSString *)initStringWithFormat: (NSString *)format, …;

If the method returns a certain object (id type) or class (Class type), we can use the embedded syntax of the
call:
[myLabel setText: [[NSString stringWithString: @”Hello”] stringByAppendingString: @” wor

Here, value of the text invariant (that is equal to a @”Hello world” string) is set for the object of the UILabel
class from the UIKit framework. This string in its turn is created by the concatenat ion of @”Hello” and @”
world” strings. The first is a result of sending of stringWithString message to a NSString class with a
@”Hello” parameter-constant. Such call returns the object of the NSString class that is initialized by a string-
parameter. Then, the stringByAppendingString message with @” world” parameter is sent to this method.
The result of sending this message is the object of the NSString class that contains concatenation of the value of
the object-receiver and string argument. This object gets as a parameter to the setText: message of the myLabel
object.

Class Declaration

Let’s declare a simple class for the complex number in the Complex.h file:

1 #import <Foundation/Foundation.h> //for NSObject and NSString strings
2  
3 @interface Complex : NSObject
4  
5 {
6  
7 double _re; //invariant for a real part
8 double _im; //invariant for an imaginary part
9 NSString *_format; //format string for the description method
10  
11 }
12  
13 ‐ (id)initWithRe: (double)re andIm: (double)im; //specialized constructor
14 + (Complex *)complexWithRe: (double)re andIm: (double)im; //class method for a one‐stage cre
15 ‐ (Complex *)add: (Complex *)other; //method for addition
16 ‐ (Complex *)sub: (Complex *)other; //method for substraction
17 ‐ (NSString *)format; //method of access to _format
18 ‐ (void)setFormat: (NSString *)format; //method of _format setting
19 ‐ (double)re; //other methods of access to real and imaginary parts
20 ‐ (void)setRe: (double)re;
21 ‐ (double)im;
22 ‐ (void)setIm: (double)im;
23 @end

As we can see, the whole declaration is put into key words @interface and @end. First, invariants are declared
(in curly brackets). Methods are placed out of curly brackets. The description method is absent in the class
declaration not accidentally. It is present in the class definition as well as the dealloc and init method. When
sending a description message to an object of the Complex class, its local list of selectors will be examined.
After compilation, selectors of all methods implemented by the class of this object and even not declared in the
interface part will get into this list. It means that init, description, and dealloc will be called correctly.

6 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

Creation of Objects

All objects are allocated in the dynamic memory, that is why we need to create an object in two steps:

1. memory allocation (alloc message) and


2. initialization of invariants (class constructors).
MyClass *myObject = [[MyClass alloc] init]; //method of the MyClass alloc class allocate

After the creation of an object, we can use it:

1 NSMutableArray  *array = [[NSMutableArray alloc] init]; //we create a variable array
2 MyClass  *myObject = [[MyClass alloc] init]; //our object [myObject myMethod]; //sending  of 
3 [array  addObject: myObject]; //we place the object to the array
4 MyClass  *otherObject = [array getLastObject:]; //we take it from the array, point to it  usi
5 [otherObject  myOtherMethod: YES]; //we send it another message with an argument of the BOOL 

Some classes possess a method for quick (one-stage) creation of their own instances. Such methods are class
methods, they return a pointer to an object of their own class and their name usually starts with the name of the
class itself. For example, the following method:
+ (NSString *)stringWithCString: (char const *)string encoding: (NSStringEncoding)encodi

It returns the ready string that is initialized by the corresponding string with a final zero without calls of alloc
and init:
NSString *myString = [NSString stringWithCString: “Bla-bla-bla” encoding: NSASCIIStringE

Object Lifetime

As soon as the pointer to an object goes beyond the scope, memory that is allocated for it is lost (if that is the last
pointer to that object) and leaks. The paradigm of calculation of references to resources is supported in
Objective-C to avoid such unwanted effects. Thus, each object has an integer counter that displays the number
of pointers that refer to it. When this counter reaches zero, memory allocated for this object returns to the
system. This counter is equal to 1 after the call of the method of the alloc class. We need to send a retain
message to an object to increase its value and release message to decrease the value. NSObject implements all
these methods. Any our class inherits it. It is interesting to note that value of the counter for static objects of the
NSString class (for example, @”I am a string”) is equal to -1, i.e., the maximum possible. Here is an example of
work with the counter:

1 id anObject = [SomeClass alloc]; //first, the counter == 1
2 anObject = [anObject init]; //here, object invariants are created
3 [anObject reatin]; //we increase its value (now, it is equal to 2)
4 [anObject release]; //then, we decrease it (the counter is equal to 1 again and the object is
5 [anObject release]; //the counter is zeroed; invariant counters are decresed by 1 and memory 

Implementation of init is very important. It is the class constructor. Constructors differ in that they return id
and their names always start with the word init, and the constructor by default is init itself. The scheme of
any constructor is like the one below:

1 ‐ (id)init
2 {
3   self = [super init]; //we call the constructor of a basic class for initialization of its 
4  

7 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

5   if (self) //if everything succeeded in the constructor of a basic class and it returned a 
6   {
7     //we can initialize our invariants
8   }
9  
10   return self; //and return itself
11 }

Here is a typical specialized (not default) constructor for a class with two members of a type of a certain class
and with one integer invariant:

1 ‐ (id)initWithInt: (int)number
2 {
3   if (self = [super init])
4   {
5     _myMember1 = [[SomeClass alloc] init]; //we allocated memory and then initialized it
6     _myMember2 = [[SomeClass alloc] init];
7     _myIntMember = number; //here, we initialize a constructor by a passed parameter – just 
8   }
9   return self;
10 }

Implementation of release and retain for NSObject is ideologically as the shown below and we do not need to
redefine it in derivative classes due to absence of access to the invariant of references counter:

1 ‐ (void)retain
2 {
3   [_internalLock lock]; //locking for synchronization
4   _referenceCounter++; // supposing that _referenceCounter is a hidden invariant of a counte
5   [_internalLock unlock];
6 }
7  
8 ‐ (void)release
9 {
10   [_internalLock lock];
11   _referenceCounter‐‐; //we decrease the counter
12  
13   if (!_referenceCounter) //if it is equal to zero
14   {
15     [_internalLock unlock];
16     [self dealloc]; // (here, locking will release)
17   }
18  
19   [_internalLock unlock];
20 }

It means that dealloc message is sent to the object itself. In the implementation of its method it can decrease
counters of its invariants if necessary and pass the similar message to an object of a basic class so that it makes
the same. It is obvious that implementation of a dealloc method for NSObject will release memory allocated for
the object. Usually, dealloc for a certain class looks as follows:

1 ‐ (void)dealloc
2 {
3   [_myMember1 release]; //we decrease the counter of our invariant
4   [_myMember2 release]; //we decrease the counter of another our invariant
5 //[_myIntMember release]; it does not have any sense; embedded types do not receive messages 
6   [super dealloc]; //let’s tell an object of a basic class that it’s time to release memory
7 }

8 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

Access Methods

A correct work with the calculation of references is very important when returning the object address from the
method or when initializing invariant using a formal parameter. Usually, the so-called access methods are used
for such things. They return and set invariants of objects. It is good practice to name the method that returns the
invariant value in the same way as the invariant and to start the name of the method that sets its value with the
set word:

1 ‐ (void)setRe: (double)re
2 {
3   _re = re;
4 }

The _re invariant refers to the embedded type so there will be no difficulties with change of its values. But if the
invariant is an object of a certain class, a simple assignment is not enough because we need to take into account
reference counters. The following three methods are applied to solve this problem:

1 //for example, we need to change the label text
2 [label setText: @"Hello world"]; //we set the text invariant
3 //of a label object equal to text constant of NSString * type
4  
5 //approximate implementation of setText in UILabel class (variant №1)
6 ‐ (void)setText: (NSString *)text
7 {
8   [text retain]; //we increase the reference counter to a formal parameter
9   [_text release]; //we decrease the reference counter of the current value of our _text inv
10   _text = text; //we initialize the invariant with a new value
11 }
12  
13 //approximate implementation of setText in UILabel class (variant №2)
14 ‐ (void)setText: (NSString *)text
15 {
16   if (_text != text) //we compare pointers to objects
17   {
18     [_text release]; //we decrease the reference counter of the current value of our _text i
19     _text = [text retain]; //we increase the reference counter to a formal parameter and ini
20   }
21 }
22  
23 //approximate implementation of setText in UILabel class (variant №3 – undesirable)
24 ‐ (void)setText: (NSString *)text
25 {
26   if (_text != text)
27   {
28     [_text autorelease]; //we throw the current value of our _text invariant to a autoreleas
29     _text = [text retain]; //we increase the reference counter to a formal parameter and ini
30   }
31 }

Variant №3 is not very good because it obstructs the current autorelease pool and it is usually undesirable (see
the next part). Method of access for reading the value of invariant is always very simple:

1 ‐ (NSString *)text
2 {
3   return _text;
4 }

Autorelease Pool in Program Threads

9 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

Now, let’s try to return an object created inside the method:

1 ‐ (NSString *)sayHelloToName: (NSString *)name withSurname: (NSString *)surname
2 {
3   NSString *retString = [[NSString alloc] initWithFormat: @”%@ %@!”, name, surname]; //we ini
4 }

The format string corresponds to C language standard. But if we need to define the id type in it, we use the
format specificator - %@. How does the method that parses the format understand, which symbols to place
instead of id? It will just place what the description method of the current object will return. This method is
initially declared for the NSObject class. NSString redefines it to the output of its string contents. Having
redefined it, any object can represent its string contents. For example, the class of a complex number with two
invariants of the double type can perform this as follows:

1 ‐ (NSString *)description
2 {
3   return [NSString stringWithFormat: @”re: %lf im: %lf”, _re, _im]; //it returns the @”re: 1.
4 }

There will be a memory leak after performing the sayHelloToName:withSurname: method. The calling code
will not guess that the release message must be sent to the returned object after processing. Even if it performs
that, it can happen that the pointer to object invariant is returned and it means that its deletion can have serious
consequences. It would be great to have a mechanism of self-release of objects in future so that the user code did
not need to release them. This problem can be solved with the help of an object of the NSAutoreleasePool class
– autorelease pool of objects. We can send the autorelease message to all objects created after the creation of
an object of such class. Such object is placed to the current (the last created) autorelease pool. When a certain
pool receives the release message, it sends the same message to all its objects. It also decreases their reference
counter (in fact, deleting it). Thus, an object placed into the autorelease pool continues living and occupies
memory during the whole pool life. It is convenient for small temporary objects but it can occupy a significant
part of the memory with the course of time. That is why it is recommended to frame cycles that can create a lot
of temporary objects, which move to the autorelease pool, with the local (embedded) pools. Any thread in the
program that uses Cocoa must create an object of the NSAutoreleasePool class in the beginning (before
creating other objects) and delete it at the end (after deleting all other objects). The main() function that is the
main thread of any program in Objective-C must look like this when using the Cocoa framework:

1 int main(int argc, char *argv[]) // or just main()
2 {
3   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //we create a pool and it becom
4   int retVal; //now we can develop
5   [pool release]; //we release the pool and all objects that are placed to it using the autor
6   return retVal;
7 }

And the correct sayHelloToName:withSurname: method will look like this:

1 ‐(NSString *)sayHelloToName: (NSString *)name withSurname: (NSString *)surname
2 {
3   NSString *retString = [[NSString alloc] initWithFormat: @”%@ %@!”, name, surname]; //we ini
4   return retString;
5 }

Besides, the drain method of the autorelease pool is similar to release. The only difference is that except the
release of itself and other objects contained in it, it prompts the garbage collector to go in. But it is actual only

10 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

for Mac OS 10.4 and higher because iOS does not have the garbage collector.

Class Definition

Now, let’s examine the Complex.m file with the definition of methods of the Complex class:

1 #import “Complex.h”
2  
3 @implementation Complex
4 ‐ (id)init
5 {
6   return [self initWithRe: 0.0 andIm: 0.0];
7 }
8  
9 ‐ (id)initWithRe: (double)re andIm: (double)im
10 {
11   if (self = [super init])
12   {
13     _re = re;
14     _im = im;
15     _format = @”re: %.1lf im: %.1lf”; //output format by default
16   }
17 }
18  
19 + (Complex *)complexWithRe: (double)re andIm: (double)im
20 {
21   return [[[Complex alloc] initWithRe: re andIm: im] autorelease];
22 }
23  
24 ‐ (Complex *)add: (Complex *)other
25 {
26   return [[Complex alloc] initWithRe: _re + other‐>_re andIm: _im + other‐>_im];
27 }
28  
29 ‐ (Complex *)sub: (Complex *)other
30 {
31   return [[Complex alloc] initWithRe: _re – other‐>_re andIm: _im – other‐>_im];
32 }
33  
34 ‐ (NSString *)format
35 {
36   return _format;
37 }
38  
39 ‐ (void)setFormat: (NSString *)format
40 {//standard order of actions for invariant‐object
41   [format retain];
42   [_format release];
43   _format = format;
44 }
45  
46 ‐ (double)re
47 {
48   return _re;
49 }
50  
51 ‐ (void)setRe: (double)re
52 {
53   _re = re;
54 }
55  
56 ‐ (double)im
57 {
58   return _im;
59 }
60  

11 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

61 ‐ (void)setIm: (double)im
62 {
63   _im = im;
64 }
65  
66 ‐ (NSString *)description
67 {//we use the set output format
68   return [NSString stringWithFormat: _format, _re, _im];
69 }
70  
71 ‐ (void)dealloc
72 {
73   [_format release]; //dealloc was redefined for this
74   [super dealloc];
75 }
76 @end

By default, the constructor calls the specialized constructor with the defined initial parameters. The
complexWithRe:andIm: method returns the initialized object of the Complex class that is located in the current
autorelease pool. The description method performs the same and returns the object of the NSString class. Here
is an example of a program where the Complex class is used:

1 #import “Complex.h”
2 #import <stdio.h>  //for printf()
3  
4 int main()
5 {
6   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
7   Complex *num1 = [[Complex alloc] init]; //0.0+0.0*i
8   Complex *num2 = [[Complex alloc] initWithRe: 1.5 andIm: ‐2]; //1.5‐2.0*i
9   Complex *num3 = [Complex complexWithRe: 5 andIm: 7]; //5.0+7.0*i
10   printf(“%s\n”, [[num2 description] cStringUsingEncoding: NSASCIIStringEncoding]); //output
11   printf(“%s\n”, [[[num2 add: num3] description] cStringUsingEncoding: NSASCIIStringEncoding
12   [num1 setRe: [num2 re]]; //set  _re for num1 as in num2
13   [num1 setIm: [num3 im]]; //set _im for num1 as in num3
14   [num1 setFormat: @”%.2lf+%.2lf*i”]; //change the output format for num1
15   printf(“%s\n”, [[num1 description] cStringUsingEncoding: NSASCIIStringEncoding]); //output
16   [num1 release];
17   [num2 release];
18 //[num3 release]; it is not required as it is already in the autorelease pool
19   [pool drain];
20  
21   return 0;
22 }

Categories and Extensions


Categories help to add/redefine some methods without inheritance from an already written (or, maybe, compiled
one) class:

1 //file “CategorizedComplex.h”
2 #import “Complex.h”
3  
4 @interfce Complex (CategorizedComplex)
5  
6 ‐ (Complex *)mul: (Complex *)other;
7 ‐ (Complex *)div: (Complex *)other;
8 @end
9  
10 //file “CategorizedComplex.m”
11 #import “CategorizedComplex.h”

12 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

12  
13 @implementation Complex (CategorizedComplex)
14  
15 ‐ (Complex *)mul: (Complex *)other
16 {
17   return [Complex complexWithRe: _re * other‐>_re ‐ _im * other‐>_im andIm: _re * other‐>_im
18 }
19  
20 ‐ (Complex *)div: (Complex *)other
21 {
22   double retRe, retIm, denominator;
23   denominator = other‐>_re * other‐>_re + other‐>_im * other‐>_im;
24  
25   if (!denominator)
26     return nil;
27  
28   retRe = (_re * other‐>_re + _im * other‐>_im) / denominator;
29   retIm = (_im * other‐>_re ‐ _re * other‐>_im) / denominator;
30  
31   return [Complex complexWithRe: retRe andIm: retIm];
32 }
33  
34 @end

And we can use it as follows:

1 Categoriz?dComplex *num1 = [[CategorizedComplex alloc] initWithRe: 1 andIm: 999];
2 Complex *num2 = [Complex complexWithRe: 0 andIm: 0];
3 CategorizedComplex *num3 = [num1 div: num2]; //num3 == nil

Extensions serve as anonymous categories:

1 //file “CategorizedComplex.m”
2 #import “CategorizedComplex.h”
3  
4 @interface Complex ()
5   ‐ (void)zeroComplex; //secret method for zeroing of a number
6 @end
7  
8 @implementation Complex
9  
10 ‐ (void)zeroComplex //only methods of the class itself can use it
11 {
12   _re = 0;
13   _im = 0;
14 }
15  
16 @end

Protocols

The Objective-C protocol is a formalized declaration of a group of methods that can implement any class if
necessary (similar to class in C++ where all methods are declared with the virtual … = 0 specificator). There
can be required (@required specificator that is considered as a default one) and selective (@optional
specificator) protocol methods in the language version 2.0. If any class implemented the required protocol
methods, it is called a class that supports this protocol. Protocol and class that supports it are declared as follows:

1 @protocol MyPrinterProtocol
2 @required

13 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

3 ‐ (void)print;
4 ‐ (BOOL)switchedOn;
5 @optional
6 ‐ (void)loadPapaer: (int)numberOfPages;
7 @end
8  
9 @interface MyPrinter : NSObject <MyPrinterProtocol>
10 //now, MyPrinter implements MyPrinterProtocol methods
11 {
12   BOOL _state;
13   int _numberOfPages;
14 }
15 ‐ (id)initWithState: (BOOL)state andPagesCount: (int)pages;
16 ‐ (BOOL)state;
17  
18 @end

We can send the print and switchedOn messages to an object of the MyPrinter class. After checking for
respondsToSelector:, we can send the loadPaper: message as there must be definitions of the similar
methods in its implementation. The declaration of an object of a class that supports a certain protocol is
performed in as follows:
MyPrinter *printer; id anotherPrinter = [[MyPrinter alloc] init]; [anotherPrinter print];

Besides, one class can support several protocols. For this, we can enumerate them using commas in brockets in
the class declaration.
@interface MyPrinter : NSObject <MyPrinterProtocol, OtherProtocol>

We should write such line to declare an object of an unknown class (id) that corresponds to a certain protocol:
id <MyPrinterProtocol> somePrinter;

Exceptions

There are two main approaches for errors processing: global status variable, whose value informs about the
success of execution of a previous operation, and generation of exceptions. Their main point is: the code where
an error occured expects that this error can be solved by the code that called it. That is why it returns the control
to this code and informs about the situation that happened in detail. Objective-C supports both these approaches.
Exception is an object of a certain class. It carries certain information about the occured situation (even by its
type). There is an NSException class in Cocoa that can be initialized using two NSString objects and one object
of any class (id type):
- (id)initWitnName: (NSString *)name reason: (NSString *)reason userInfo: (id)userInfo;

We can generate exceptions and start the mechanism of unwinding of call stack with the help of the @throw
operator. To intercept the generated exception, we need to enclose the part of the code where generation is
possible in a special block with a @try heading (such blocks can be embedded). Then, after this block, we need
to place a block with a @catch() heading where we need to define the type of the supposed exception in round
brackets. There can be several @catch() blocks after the @try block. After the exception generation, control
unwinds stack and leaves the @try block. Then it checks all @catch() blocks one by one and gets into the
@catch() block in whose curly brackets the type, which the exception type is converted to indirectly (exact
match, pointer to basic class or id), stands. If an exception by type did not match any @catch() block, control
continues the stack unwinding. If there is a block with @finally heading after the block with a @try heading,
control is passed to it independently if exception occurred in the @try block (and some @catch() block is
processed), or its last instruction is executed. Here is an example of work with an object of Cup class (exception
occurs in its fill method):

14 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

1 Cup *cup = [[Cup alloc] init];
2  
3 @try
4 {
5   [cup fill]; //an exeption of the NSException type is generated to fill
6 }
7 @catch (NSException *exception)
8 {//we log the occurred exception with the help of NSLog
9   NSLog(@"main: Caught %@: %@", [exception name], [exception reason]);
10 }
11 @finally //we get here after @try
12 {
13   [cup release];
14 }

In the @finally block, it is good to release resources that are allocated in the @try block but that are not
released due to generated exception.

Properties

Our implementation of the Complex class is redundant for Objective-C 2.0. There are a lot of access methods in
it and their definition is a rut. Let’s rewrite it using the properties:

1 //“Complex.h” file
2 #import <Foundation/Foundation.h>  //for NSObject and NSString strings
3  
4 @interface Complex : NSObject
5 {
6   double _re; //invariant for a real part
7   double _im; //invariant for an imaginary part
8   NSString *_format; //format string for the description method
9 }
10 ‐ (id)initWithRe: (double)re andIm: (double)im;
11 + (Complex *)complexWithRe: (double)re andIm: (double)im;
12 ‐ (Complex *)add: (Complex *)other; //method for addition
13 ‐ (Complex *)sub: (Complex *)other; //method for substraction
14 @property (nonatomic, retain) NSString *format; //we declare access methods
15 @property (nonatomic, assign) double re; //by means of declaration of properties
16 @property (nonatomic, assign) double im;
17 @end
18  
19 //file “Complex.m”
20 #import “Complex.h”
21  
22 @implementation Complex
23 @synthesize format = _format; //we generate access methods
24 @synthesize re = _re; //and rename them at the same time
25 @synthesize im = _im; //so that there is no underlining in the name
26 ‐ (id)init
27 {
28   return [self initWithRe: 0.0 andIm: 0.0];
29 }
30 ‐ (id)initWithRe: (double)re andIm: (double)im
31 {
32   if (self = [super init])
33   {
34     _re = re;
35     _im = im;
36     _format = @”re: %.1lf im: %.1lf”; //output format by default
37   }
38 }
39  
40 + (Complex *)complexWithRe: (double)re andIm: (double)im

15 of 16 8/25/2013 11:22 AM
Objective-C from the Scratch http://www.apriorit.com/dev-blog/241-objective-c-from-the-scratch?tmp...

41 {
42   return [[[Complex alloc] initWithRe: re andIm: im] autorelease];
43 }
44  
45 ‐ (Complex *)add: (Complex *)other
46 {
47   return [[Complex alloc] initWithRe: _re + other.re andIm: _im + other.im]; //we use re and
48 }
49  
50 ‐ (Complex *)sub: (Complex *)other
51 {
52   return [[Complex alloc] initWithRe: _re – other.re andIm: _im – other.im]; //we use re and
53 }
54  
55 @end

Property is a certain name that is available via the pointer to an object by means of point operator “.”. Properties
are used instead of access methods to get or set the object invariant. A row of parameters that describe specifics
of access methods generated by a property are defined during the declaration of a property.

getter=getterName, setter=setterName - Defines that the access method for reading will be called
getterName and for changing - setterName
readonly – Not to generate the access method for changing
readwrite – To generate both access methods
assign – To generate the access method for changing by means of simple assignment
retain - To send the retain message to the accepting value; to send the release message to the previous
invariant value and to assign the accepted value to it
copy - To use a simple assignment operator but to assign the copy of the accepted value (before
assignment, the copy message is sent to it)
nonatomic – Not to use internal lockings for synchronization of several threads in generated access
methods (synchronization is used by default)

Now, we do not need to write access methods manually in the definition of the Complex class. They will be
generated by a compiler and will be identical to those that were before.

And of course, a theory in studying of programming language will not replace the practice. So, install Xcode
quicker :)

Do you like our specialists' work? Make them work for you!

16 of 16 8/25/2013 11:22 AM

You might also like