Apple iOS dev
Raiting:
1

How to learn Objective-C


imageIn the life comes a moment, when anyone who wishes to write programs for the products of Apple company has to learn a new programming language Objective-C.

Here is a banal theory of the object-oriented programming (OOP) appearance


The problem of reusing a written code and its portability make the programmers constantly look for the new ways to organize, structure and abstracting it. In order to solve these problems are created the new programming paradigms, design template tooling, new languages, compilers, standard libraries, software platforms and frameworks. Thus were formed the paradigm of subprograms (procedures) that is implemented by the processor’s commands CALL \ RET and the stack (in fact, moving the implementing stream at the address of random rather than following the current command with further return). Then, the paradigm of modules (each file is a separate translation unit) that produced a two-stage translation: compilation of modules and their linking (static or dynamic) in the executable module.

Since 1960 has begun to form a new object-oriented programming paradigm that divided the programs into smaller components of data types in consequence of increasing the size of code in the projects and the complexities of its support. Its essence lies in the interaction of entities (objects), which sends to each other messages. Each object is a variable of data types (so-called a class) that is defined by the programmer. Determination of a special user data type (class) is defined by two things: determination a set of data (invariants and members) and a set of subprograms (methods) that will support them.

image

The class is usually made as a programmer-defined type based on built-in (language) data types and \ or other classes. For the C language that does not support an object-oriented paradigm, it could be a structure of (struct). A set of subprograms that are implemented as the ordinary functions and it requires taking at least one parameter, an indication to a set of data to be processed.

The main advantage of object-oriented approach is the ability to create the new classes based on already written (add invariants and methods, override methods, use defined methods in the base class as own) that are called inheritance.

image

The set of methods is an interface for interaction with invariants. You cannot directly modify the data class (without using its interface) this reflects the principle of encapsulation. The figure shows the class and its objects. There is invariant x of type float with the interface (method) doubleX that returns the value of the invariant.

Sometimes, it is necessary to send a message to the object, which definitely responds to it (i.e. call such method for a class object, which was implemented), but a particular class of this object is unknown in this situation. For example, it has to be sent a message Move for each element of a pointers’ list to objects of class Auto, and it is known that the list has pointers to objects of class Auto and also the pointers to derivatives (inherited) classes such as Ford and Subaru. This is possible to make only through the principle of polymorphism, which consists in the fact that when it is sent a specific message to an object of a certain class hierarchy that all objects are capable to receive such message, the object reacts to it according to its, class and it does not respond to the basic of given hierarchy of class.

The first language to support object-oriented approach was Simula67. Then there was Smalltalk. In the 1980s C + + began to take shape, which is the main language of modern system programming. Its expansion and improvement led to a number of paradigms and design template tooling in the 1990s, and it has had an irreversible impact on the modern view of object-oriented approach, including the language Objective-C.

Short history


A language Objective-C appeared in the 1980s as a modification in the direction of Smalltalk. Moreover, this modification consisted of addition of the new syntax structures and a special preprocessor for them (converted them into ordinary C function calls, which pass by the code), as well as the run-time library. Thus, the Objective-C was originally seen as an add-on at C. In a sense, this is the case so far: you can write a program in pure C, and then add to it some structures from Objective-C (if it is necessary), or vice versa, use C in the programs in Objective-C. In addition, all this applies to programs in C + +. NeXT (later Apple) has licensed the Objective-C and written a compiler and standard library (SDK) for it in 1988. In order to improve the language and compiler the developers of the GNU project have joined within the scope of OpenStep project in 1992. Since that time GCC supports Objective-C. Apple took SDK (compiler, libraries, IDE) as the basis for its further development after buying neXT. IDE was called Xcode and GUI was renamed as Interface Builder. Cocoa for GUI development is currently the most important environment of program development in the Objective-C.

Here are the special features of Objective-C


Plug-in files have the extension “.m” in Objective-C (if you use a mixture of C + + and Objective-C, then the extension is ".mm"). The header files have the extension ".h". All created the class’ objects in Objective-C should be allocated in the DRAM. Therefore, the special importance gets the type id, which is a pointer to the object of any class (void*). A zero pointer is called constant nil. Thus, a pointer to any class can be brought to type id. The problem arises: how do you know which class is the object that hiding under the id? This is done through the invariant isa, which is present in any object of class, which inherited a special basic class NSObject (a prefix NS indicates NeXT Step). Isa invariant refers to the reserved type Class. The object of this type can recognize the names of its class and the base class, a set of invariants of the class, as well as prototypes of all methods, which were implemented by this object and their addresses (using the local list of selectors). All reserved words of Objective-C that are different from the reserved words of C start with the symbol @ (e.g. @protocol, @selector, @interface). Usually the invariant names of classes with limited scope (@private, @protected) begin with an underscore. Cocoa has a very convenient class NSString for strings. A string constant of such class is written as @"Hello world", but it is not written as usual for the C string constant "Hello world". Type BOOL (actually unsigned char) can take constant values YES and NO. All special reserved words for Objective-C (which are different from the C language and are in the header file objc/objc.h) are listed below:

• @interface begins the class’ declaration or category (category - extension of the class with additional methods without inheritance)
• @implementation begins the definition of a class or category
• @protocol begins the protocol’s declaration (similar to C + + class that consists of pure virtual functions)
• @end completes the declaration\definition of any class, category or protocol
• @private limits the scope of the class invariants by class’ methods (like C + +)
• @protected remains as the default. It limits the scope of class invariants by class’ methods and methods of derived classes (like C + +)
• @public deletes restrictions on the scope (like C + +)
• @try defines a block with the possible generation of exceptions (like C + +)
• @throw generates exception-object (like C + +)
• @catch () processes the exception that is generated in the preceding block @try (like C + +)
• @finally defines a block after block @try, where is given the control regardless of generated exception
• @class short form of the class declaration (only the name (like C + +))
• @selector(method_name) returns the compiled selector for the method_name
• @protocol(protocol_name) returns an instance of class’ protocol with protocol_name
• @encode(type_spec) initializes the string of characters that will be used to encrypt the data type_spec
• @synchronized () defines a block of code that is run only by one thread at any given time

Message passing


A message should be sent in order to make an object to perform any method that is referred to as well as the required method. This message is called a selector of the method. Syntax is as follows:

[receiver method];
image

The message can pass parameters to the called method:

[receiver method: 20.0 : 30.0];
Before each parameter must be a colon. A number of colons defines the number of parameters. The name of the method can continue after each colon-parameter:

[receiver methodWithFirstArgument: 10 andSecondArgument: 20];
Methods with unlimited number of arguments are called by the following syntax:

[receiver undefinedNumberParameters: one, two, three, four, five, six, seven];
Sending a message, as well as any function of C returns defined (perhaps void) value:

BOOL booleanValue;
booleanValue = [reveiver method];

It just disappears when sending a message nil. When sending a message to an object, which belongs to the class that is not implemented, the ordered method appears an exception, which was not intercepted; it leads the entire program to an unexpected termination. In order to check whether the object responds to any message, you can use the following template code:

if ( [anObject respondsToSelector: @selector (myMethodWith2Argumets ::) ] )
{
// it can be called
[AnObject myMethodWith2Argumetns: @"first" : @"second"];
}
else
{
// In any case cannot be called
}

How does the message passing work?


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

id objc_msgSend (id receiver, SEL method, ...) ;
In fact, type SEL is defined as char const *, but it is better to take it as int since during the execution all the selectors are indexed by integer values according to the global table selectors.

image

Using an invariant object isa receiver (using the framework Foundation that is basic for Cocoa, all classes must inherit class NSObject, so the presence of isa is unavoidable), this function scans the local list of class’ selectors to determine whether the object of this class to a message method. If a selector is located, then control is transferred to the appropriate class’ method, which is given the object’s id (a pointer to its invariants) that is specified after the selector function parameters objc_msgSend(). The value that is returned by the method is given as a result of sending the message. If the object-receiver does not have this selector, the function objc_msgSend() scans the list of selectors of its base class.

image

Example:

[receiver addObject : otherObject] ;
Compiles into:

objc_msgSend (receiver, 12, otherObject);
As the global table has 12selectors, which corresponds to a string "addObject:". Next function objc_msgSend () searches the list of selectors of object receiver and when finds it (even if it is an object of class NSArray, which implemented the method with the selector 12), it makes a call like:

addObject (receiver, otherObject) ;

Method’s declaration


The prototype of the method addObject looks like this from the previous section in the class declaration:

- (void) addObject: (id) otherObject;
It took only one parameter. But based on the principle of object-oriented paradigm, that the methods are paradigms that process the specific sets of data, the method must pass an address data in order to be processed. Therefore, this parameter is passed indirectly in every class’ method. The compiler knows of this additional parameter because of minus ("-") that stands as a first in the prototype of method. This method (with a minus in front) is called the method of object (or instance), because it can be called only for the object of a class. In the body of this method is a pointer to the instance of data (or address of the object that was sent the message) that is available by the use of the keyword “self” (an analogue of this in C + +), and a pointer to a base class is through the keyword “super”. In addition, the method of the object is passed an implicit parameter _cmd, which is a selector of the method from the global table selectors. All methods of objects as if declared with the keyword “virtual” in Objective-C from the perspective of a programmer of C + +, and always follow the dynamic polymorphism.

If at the beginning of the prototype’s method to put a plus sign ("+"), then this method will be considered as the class’s method, and it will not accept the implicit parameter “self” (this is similar to declaration’s static method in C + +). As well without invariant object of isa, which is pointed by “self” a pointer “super” will not work.
Thus, the prototype of any method is declared as follows:

- | + (<type of return value>) basic part of method’s name
[: (<type of first parameter>) name of first dummy parameter
[[additional part of method’s name]: (<type of second parameter>) name of second dummy parameter
...]</code.

For example:

<code lang="cpp">+ (Class) class;
+ (id) alloc;
- (id) init;
- (void) addObject: (id) anObject;
+ (NSString *) stringWithCString: (const char *) aCString usingUncoding: (enum NSStringEncoding) encoding;
- (NSString *) initStringWithFormat: (NSString *) format, ...;

If the method returns an object (type id) or class (type Class), you can use a nested syntax of call:

[myLabel setText: [[NSString stringWithString: @"Hello"] stringByAppendingString: @"world"]];
Here is set a value of invariant text equal to a string @"Hello world" for the object of a class UILabel from UIKit framework. This string is formed by the concatenation of strings @"Hello" and @"world". The first is the result of sending a message stringWithString to the class NSString with a constant-parameter @"Hello". This call returns an object of class NSString, which is initialized by the string-parameter. Then the object is sent a message stringByAppendingString with a parameter @"world". The sending result of this message is an object of class NSString that contains a concatenation of the value of object-receiver and a string argument. This object gets as a parameter in the message setText: object myLabel.

Class’ declaration



Let us declare a simple class of a complex number in the file Complex.h:

# import <Foundation/Foundation.h> // for NSObject and NSString

@interface Complex : NSObject
{
double _re; // invariant for the real part
double _im; // invariant for the imaginary part
NSString * _format; // format string for a method description
}
- (id) initWithRe: (double) re andIm: (double) im; // special constructor
+ (Complex *) complexWithRe: (double) re andIm: (double) im; // class’ method for one-step creation of an object
- (Complex *) add: (Complex *) other; // method for adding
- (Complex *) sub: (Complex *) other; // method for subtracting
- (NSString *) format; // access’ method to _format
- (void) setFormat: (NSString *) format; // method of installation _format
- (double) re; // other methods of access to the real and imaginary parts
- (void) setRe: (double) re;
- (double) im;
- (void) setIm: (double) im;
@end

As we can see all declaration is enclosed in the keywords @interface and @end. First, invariants are declared (in brackets). Outside the brackets are declared methods. The method of description is not in the class declaration. The fact is that it like the methods dealloc and init are present in the class’s determination. When it sends a message to an object of class Complex the description will consider its local list of selectors, where the selectors of all the methods will get after compilation that are implemented by the class of the object, even which are not declared in the interface part. That is “init”, the description and dealloc will call absolutely correct.

Creating objects


Due to the fact that all objects are allocated in DRAM to create the object has to be done in two stages: 1) the allocation of memory (message alloc) and 2) initialization of the invariants (class’ constructors).

MyClass *myObject = [[MyClass alloc] init]; // class’ method MyClass alloc allocates a memory section of required size and returns a pointer to it, the method of object “init” initializes the invariants of object myObject
Once it created, you can safely use them:

NSMutableArray *array = [[NSMutableArray alloc] init]; // create a mutable array
MyClass *myObject = [[MyClass alloc] init]; / / our object
[MyObject myMethod]; // sending a message
[Array addObject: myObject]; // put the object into an array
MyClass *otherObject = [array getLastObject:]; // get it out from the array and point to it a different pointer
[OtherObject myOtherMethod: YES]; // send to it another message with an argument of type BOOL

Some classes have a rapid method (in one step) to create own instances. Such methods are class’ methods that return a pointer to the object of their class and their name usually begins with the name of the class. For example: the method:

+ (NSString *) stringWithCString: (char const *) string encoding: (NSStringEncoding) encoding;
It returns a ready-made string that is initialized by the appropriate string with a completed zero without calls alloc and init:

NSString * myString = [NSString stringWithCString: "Bla-bla-bla" encoding: NSASCIIStringEncoding];

Lifetime of the object


As soon as a pointer to an object is outside its scope, the memory that is allocated for it is lost irretrievably (unless, it was the last pointer to the object) and a leak happens. In order to avoid such undesirable consequences supports the paradigm of the counting of links to resources in Objective-C. Thus, each object has an integer counter that indicates the number of pointers that refer to it. When this counter gets to zero the memory, which is allocated for the object returns to the system. After calling a class’ method alloc this counter is equal to one. In order to increase its value, it is necessary to send a message “retain” to the object, and to reduce – “release”. All of these methods are implemented by the NSObject that any of our class will certainly inherit. It is interesting to note that the counter value for the static objects of class NSString (eg @"I am a string") is equal 1, that is the maximum possible. Here is an example how to work with the counter:

id anObject = [SomeClass alloc]; // first is counter == 1
[anObject init]; // here are created the invariants of the object
[anObject reatin]; // increase its value (now == 2)
[anObject release]; // reduce (counter is == 1 again and the object is still viable)
[anObject release]; // counter is reset to zero, counters of invariants reduced to 1 and the object memory that is allocated for the object returns to the operating system


The implementation of “init” is very important. This is the constructor of the class. Constructors are different, because they return id and their names always begin with the word “init”, and the default constructor is just init. The scheme of any constructor looks like this:

- (id) init
{
self = [super init]; // call the base class’ constructor for
// initialization its invariants
if (self) // if everything went well in the base class’ constructor
// and it returned the correct object, not nil
{
/ / then here you can safely initialize the invariants
}
return self; // and return itself
}

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

- (id) initWithInt: (int) number
{
if (self = [super init])
{
_myMember1 = [[SomeClass alloc] init]; // all as it should be: allocated memory, then it is initialized
_myMember2 = [[SomeClass alloc] init];
_myIntMember = number; // here constructor is useless
// initialize the transferred parameter
}
return self;
}

The implementation of release and retain for NSObject ideologically is similar to the following, and it should not be overridden in derived classes, because of lack of access to the invariant of link counter:

- (void) retain
{
[_internalLock Lock]; // lock for synchronization
_referenceCounter++; // let _referenceCounter - hidden invariant counter
[_internalLock unlock];
}
- (void) release
{
[_internalLock Lock];
_referenceCounter -; // reduce counter
if (! _referenceCounter) // if it is zero
{
[_internalLock unlock];
[self dealloc]; // lock released here
}
[_internalLock unlock];
}

The object is sent a message dealloc to implement the method which it can, if necessary to reduce the counters of invariants and give a similar message to an object of the base class, so it will do the same thing. Obviously, the implementation of dealloc method for NSObject releases the memory that is allocated to the object. Usually, dealloc looks for any class as follows:

- (void) dealloc
{
[_myMember1 release]; // decrease the counter of the invariant
[_myMember2 Release]; // decrease the counter of other invariant
// [_myIntMember release]; this is complete nonsense, because built-in type of messages do not accept and support counters
[super dealloc]; // it is time for the object of base class to free a memory
}

Access’ Methods


Correct work with counting the links is very important when address of an object is returned from a method or initialization of invariant by the formal parameter. Usually, these things do so-called access’ methods that return and determine the invariants of objects. Generally, this method begins with the word “set”:

- (void) setRe: (double) re
{
_re = re;
}

Since the invariant _re refers to the integrated type, there are no problems with the change in its value. But if the invariant - the object of a certain class – there are used the following three methods:

// For example: change the text in the tag
[Label setText : @"Hello world"]; // determine the invariant text of
// object label equal to text of constant type NSString *

// approximate realization setText in class UILabel (option # 1)
- (void) setText: (NSString *) text
{
[text retain]; // increase the link counter on the formal parameter
[_text release]; / / decrease the link counter of the current value of the invariant _text
_text = text; / / initialize the new value of the invariant
}

// approximate realization setText in class UILabel (option # 2)
- (void) setText: (NSString *) text
{
if (_text! = text) / / compare the pointers to objects
{
[_text release]; / / decrease the link counter of the current value
// its invariant _text
_text = [text retain]; // increase the link counter
// on the formal parameter and initialize its invariant
}
}

// approximate realization setText in class UILabel (option # 3 - unwanted)
- (void) setText: (NSString *) text
{
if (_text! = text)
{
[_text autorelease]; // put current value of its
/ / invariant _text in autorelease pool
_text = [text retain]; // increase the link counter
// on the formal parameter and initialize its invariant
}
}

Option # 3 is not very good, because it clogs the current autorelease pool, and this is not very desirable (see next section).
Access’ method to read the value of the invariant is always very simple:

- (NSString *) text
{
return _text;
}

Autorelease pool in the threads of the program


Now, we will try to return from a method that is created inside of it the object:

- (NSString *) sayHelloToName: (NSString *) name withSurname: (NSString *) surname
{
NSString * retString = [[NSString alloc] initWithFormat: @ "% @ %@!", name, surname]; / / initialize the created object by the format string
return retString;
}

The format string corresponds to the standard C language, but if it is necessary to specify the type of id, then is used the format specifier% @. How does the method parse the format understand what characters to substitute for id? It will substitute that be returned by the description method of the object. This method was originally declared for the class NSObject. NSString redefined it to output on its string of content. When it was redefined any object can represent its string content. For example, it can make a class of complex of number with the two invariants of type double:

- (NSString *) description
{
return [NSString stringWithFormat: @ "re:% lf im:% lf", _re, _im]; / / returns the string @ "re: 1.0 im: 2.5" to _re == 1.0 and _im == 2.5
}

Following the method sayHelloToName: withSurname: will leak memory, as the calling code probably does not realize that the returned object after processing needs to send a message “release”. Even if it guesses to do it, it is possible that a pointer returned to an invariant’s object, and then destroying it fraught with serious consequences. It would be nice to have a mechanism of autorelease of objects in the future, so the custom code never thought about their release. This problem is solved by using a class’ object NSAutoreleasePool of autorelease pool of objects.

After creating the object of this class can be sent messages autorelease to all objects. In this case the object is placed in the current (last created) autorelease pool. When a pool will receive release, it will send the same message to all its objects reducing their link counter (in fact, destroying it). Thus, the object that is placed in self-upload pool continues to live and occupy memory during the lifetime of the pool. This is useful for small temporary objects, but it may over time take a significant chunk of memory. Therefore, it is recommended the cycles that can generate a large number of temporary objects that are sent to autorelease pool to be bordered by the local pools.

Any thread that is using Cocoa in the program should create an object of class NSAutoreleasePool at the beginning (before the creation of other objects), and it destroys at the end (after the destruction of all other objects). Function main (), which is the main thread of every program in the Objective-C when using Cocoa framework it should always look like this:

int main (int argc, char * argv []) // or just main ()
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // create the pool, it automatically becomes the current
int retVal;
// now it can be programmed easily
[pool drain]; // release the pool and all the objects that are placed in it using autorelease
return retVal;
}

A correct method sayHelloToName: withSurname: now it will look like this:

- (NSString *) sayHelloToName: (NSString *) name withSurname: (NSString *) surname
{
NSString * retString = [[NSString alloc] initWithFormat: @ "% @ %@!", name, surname]; // initialize the created object by the format string
[retString autorelease]; // put in the pool, now retString releases along with a pool
return retString;
}

By the way, the method drain of autorelease pool is similar to release with the only difference that besides its autorelease and all contained objects, it gives a clue to the cleaner to start its work. However, it is relevant only for Mac OS 10.4 and above.

Class’ definition


Now consider the file Complex.m with definition of methods of the class Complex:

# Import "Complex.h"

@ Implementation Complex
- (Id) init
{
return [self initWithRe: 0.0 andIm: 0.0];
}
- (Id) initWithRe: (double) re andIm: (double) im
{
if (self = [super init])
{
_re = re;
_im = im;
_format = @ "re:% .1 lf im:% .1 lf"; / / default display
}
}
+ (Complex *) complexWithRe: (double) re andIm: (double) im
{
return [[[Complex alloc] initWithRe: re andIm: im] autorelease];
}
- (Complex *) add: (Complex *) other
{
return [[Complex alloc] initWithRe: _re + other-> _re andIm: _im + other-> _im];
}
- (Complex *) sub: (Complex *) other
{
return [[Complex alloc] initWithRe: _re - other-> _re andIm: _im - other-> _im];
}
- (NSString *) format
{
return _format;
}
- (void) setFormat: (NSString *) format
{// Standard operating procedures for the invariant object
[format retain];
[_format release];
_format = format;
}
- (double) re
{
return _re;
}
- (void) setRe: (double) re
{
_re = re;
}
- (double) im
{
return _im;
}
- (void) setIm: (double) im
{
_im = im;
}
- (NSString *) description
{// use the specified output format
return [NSString stringWithFormat: _format, _re, _im];
}
- (void) dealloc
{
[_format Release]; // for this is redefined dealloc
[Super dealloc];
}
@end

The default constructor is a special constructor with the certain initial parameters. Method complexWithRe: andIm: returns an initialized object of class Complex that is located in the current autorelease pool. The same thing does a method description returning an object of class NSString. Here is a sample of program that uses the class Complex:

# import "Complex.h"
# import <stdio.h> / / for printf ()

int main ()
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Complex * num1 = [[Complex alloc] init]; / / 0.0 +0.0 * i
Complex * num2 = [[Complex alloc] initWithRe: 1.5 andIm: -2];
// 1.5-2.0 * i
Complex * num3 = [Complex complexWithRe: 5 andIm: 7];
// 5.0 +7.0 * i
printf ("% s \ n", [[num2 description] cStringUsingEncoding: NSASCIIStringEncoding]); // output> re: 1.5 im: -2.0
printf ("% s \ n", [[[num2 add: num3] description] cStringUsingEncoding: NSASCIIStringEncoding]); / / output> re: 6.5 im: 5.0
[num1 setRe: [num2 re]]; // define _re for num1 as for num2
[num1 setIm: [num3 im]]; // define _im for num1 as for num3
[num1 setFormat: @ "% .2 lf +% .2 lf * i"]; / / change the output format to num1
printf ("% s \ n", [[num1 description] cStringUsingEncoding: NSASCIIStringEncoding]); // output> 1.50 +7.00 * i
[num1 release];
[num2 release];
// [num3 release]; it is not necessary, because it was in the autorelease pool
[pool drain];
return 0;
}

Categories and extensions


If there is a need to add or redefined to written class some methods without inheritance and categories let to do it without much effort:

// file "CategorizedComplex.h"

# import "Complex.h"
@interfce Complex (CategorizedComplex)
- (Complex *) mul: (Complex *) other;
- (Complex *) div: (Complex *) other;
@end

// file "CategorizedComplex.m"
# import "CategorizedComplex.h"

@implementation Complex (CategorizedComplex)
- (Complex *) mul: (Complex *) other
{
return [Complex complexWithRe: _re * other-> _re - _im * other-> _im andIm: _re * other-> _im + _im * other-> _re];
}
- (Complex *) div: (Complex *) other
{
double retRe, retIm, denominator;
denominator = other-> _re * other-> _re + other-> _im * other-> _im;
if (! denominator)
return nil;
retRe = (_re * other-> _re + _im * other-> _im) / denominator;
retIm = (_im * other-> _re - _re * other-> _im) / denominator;
return [Complex complexWithRe: retRe andIm: retIm];
}
@end

It can be used like this:

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

Extensions have good service as nameless categories:

// file "CategorizedComplex.m"
# import "CategorizedComplex.h"
@interface Complex ()
- (void) zeroComplex; / / hidden method to reset the number
@end

@implementation Complex
- (void) zeroComplex / / they can be used by methods of the class
{
_re = 0;
_im = 0;
}
@end

Protocols


Protocol Objective-C is a formalized declaration of a group of methods that can implement any class (similar to a class in C + +, where all methods are declared with qualifier virtual ... = 0). In a version of language 2.0 methods of protocol may be required (specificator @required) and selective (specificator @optional). If any class has implemented the required methods of the protocol, it is called a class that supports this protocol. Protocol and class, which supports it are declared like this:

@protocol MyPrinterProtocol
@required
- (void) print;
- (BOOL) switchedOn;
@optional
- (void) loadPapaer: (int) numberOfPages;
@end

@interface MyPrinter: NSObject <MyPrinterProtocol>
// now MyPrinter MyPrinterProtocol implements methods
{
BOOL _state;
int _numberOfPages;
}
- (id) initWithState: (BOOL) state andPagesCount: (int) pages;
- (BOOL) state;
@end

Object of class MyPrinter can be sent messages print and switchedOn, and after checking for respondsToSelector:, you can send a message loadPaper:. Declaring an object class that supports any protocol can be done as follows:

MyPrinter *printer;
id anotherPrinter = [[MyPrinter alloc] init];
[anotherPrinter print]; // unnamed object responds to a message without compiler warnings

In addition, one class might satisfy a number of protocols. In order to do this, you can list them separate by commas within the angle brackets in the class’ declaration.

@interface MyPrinter: NSObject <MyPrinterProtocol, OtherProtocol>
In order to declare an object of unknown class (id) that corresponds to a certain protocol, write this:

id <MyPrinterProtocol> somePrinter;

Exceptions


There are two basic approaches to error handling: a global status variable, which value informs about success of the previous operation and the generation of exceptions. The essence of both is that the code where the error occurred hopes that the calling code will solve it, so it returns a control to it and report on the occurred situation as detailed as possible. Objective-C supports both of these approaches.

The exception is an object of some class. It carries some information about the situation that occurred. For convenience Cocoa has a class NSException, which can be initialized by two objects NSString and one object of any class (type id):

- (id) initWitnName: (NSString *) name reason: (NSString *) reason userInfo: (id) userInfo;
The operator @throw can generate an exception, thus it will trigger the unwinding of the call stack. In order to intercept the generated exception, code segment, where it can be generated, it is necessary to enclose it in a special box with the title @try (such blocks can be nested). Then, after the block puts it with the title @catch () where the parentheses indicate the type of expected exceptions. Blocks @catch () may be several after the block @try. After generation of an exception control unwinds the stack and gets out of the block @try and checks out one by one all the blocks @catch (), then gets exactly in the block @catch () with the brackets, which has this type and an exception is brought implicitly (exact match, a pointer to a base class or id). If an exception type does not coincide with any of the block @catch () control continues to unwind the stack. If after a block with the title @try is a block with the title @finally, then the control is given to it whatever exception occurred in the block @try or was performed its last instruction. Below is an example of an object of class Cup in the method fill, which an exception occurs:

Cup *cup = [[Cup alloc] init];
@try
{
[cup fill]; / / in fill is generated an exception of type NSException
}
@catch (NSException *exception)
{// log occurred exception using NSLog
NSLog (@"main: Caught% @:% @", [exception name], [exception reason]);
}
@finally // here get inevitably after @try
{
[cup release];
}

In block @finally conveniently to release the resources that are allocated in the block @try, but not released because of an exception.

Properties


For the version of Objective-C 2.0 implementation of the class Complex is clearly redundant: it has too many access’ methods and their definitions, it is a solid routine. Rewrite it using the properties:

// file "Complex.h"
# import <Foundation/Foundation.h> // for NSObject and NSString

@interface Complex: NSObject
{
double _re; // invariant for the real part
double _im; / invariant for the imaginary part
NSString * _format; / / format string for a method description
}
- (Id) initWithRe: (double) re andIm: (double) im;
+ (Complex *) complexWithRe: (double) re andIm: (double) im;
- (Complex *) add: (Complex *) other; / / method for addition
- (Complex *) sub: (Complex *) other; / / method for subtraction
@property (nonatomic, retain) NSString * format; / / declare methods of access
@property (nonatomic, assign) double re; / / by the use of declare properties
@property (nonatomic, assign) double im;
@end

// file "Complex.m"
# import "Complex.h"

@implementation Complex
@synthesize format = _format; // generate access’ methods
@synthesize re = _re; // rename them
@synthesize im = _im; // no underscore
- (id) init
{
return [self initWithRe: 0.0 andIm: 0.0];
}
- (Id) initWithRe: (double) re andIm: (double) im
{
if (self = [super init])
{
_re = re;
_im = im;
_format = @ "re:% .1 lf im:% .1 lf"; / / default display
}
}
+ (Complex *) complexWithRe: (double) re andIm: (double) im
{
return [[[Complex alloc] initWithRe: re andIm: im] autorelease];
}
- (Complex *) add: (Complex *) other
{
return [[Complex alloc] initWithRe: _re + other.re andIm: _im + other.im]; / / use the properties re and im
}
- (Complex *) sub: (Complex *) other
{
return [[Complex alloc] initWithRe: _re - other.re andIm: _im - other.im]; / / use the properties re and im
}
@end

Property is a certain name that is accessible through a pointer to the object by the use of the operator's point ".". Properties are used instead of access’ methods to get or determine the object of invariant. In the property declaration are specified some parameters that describes the features, which are generated by the property access’ methods.

• getter = getterName, setter = setterName specifies that the access’ method to read will be called getterName, and to change - setterName
• readonly do not generate an access’ method to change
• readwrite generate both methods of access
• assign access’ method to implement the change with a simple assignment
• retain send a message to retain to the received value, the previous value of the invariant send release and assign the received value
• copy use an ordinary assignment operator and assign a copy of the received value
• nonatomic do not use the internal locks to synchronize the some threads in the generated access’ methods (use a default synchronization)
Now, when it is needed to define Complex class no need to write manually access’ methods. They will be generated by a compiler and be identical to those that used to be.

Good luck!
Pirat 19 november 2011, 13:38
Vote for this post
Bring it to the Main Page
 

Comments

Leave a Reply

B
I
U
S
Help
Avaible tags
  • <b>...</b>highlighting important text on the page in bold
  • <i>..</i>highlighting important text on the page in italic
  • <u>...</u>allocated with tag <u> text shownas underlined
  • <s>...</s>allocated with tag <s> text shown as strikethrough
  • <sup>...</sup>, <sub>...</sub>text in the tag <sup> appears as a superscript, <sub> - subscript
  • <blockquote>...</blockquote>For  highlight citation, use the tag <blockquote>
  • <code lang="lang">...</code>highlighting the program code (supported by bash, cpp, cs, css, xml, html, java, javascript, lisp, lua, php, perl, python, ruby, sql, scala, text)
  • <a href="http://...">...</a>link, specify the desired Internet address in the href attribute
  • <img src="http://..." alt="text" />specify the full path of image in the src attribute