I. Qu'est-ce qu'Objective-C ?

Objective-C a été créé en 1980 et est une extension du langage C. Il ajoute de nouvelles fonctionnalités au C dont la plus importante est une structure POO (Programmation Orientée Objet).

Comment créer une classe ?

La création d'une classe se fait en deux étapes en Objective-C. La première consiste à créer le fichier header ou interface (.h) et la seconde est la création du fichier d'implémentation (.m).

Le fichier header/interface est utilisé pour définir toutes les méthodes et propriétés qui seront utilisées dans votre classe.

Le fichier d'implémentation est le fichier dans lequel vous allez écrire votre code qui fait ce que vous avez décrit dans votre fichier header/interface.

Voici la syntaxe du fichier header :

 
Sélectionnez

@interface MaClasse : NSObject {
  // vous placez ici toutes vos propriétés
}
// et vos méthodes en dehors des accolades
end
				

Et du fichier d'implémentation :

 
Sélectionnez

// Vous devez absolument importer votre fichier .h
#import <MaClasse.h>
@implentation MaClasse
// vous placez ici votre code
end				
				

À noter : Xcode vous proposera de créer automatiquement le fichier header lorsque vous créerez le fichier d'implémentation.

La syntaxe

L'Objective-C possède une syntaxe assez différente des langages de programmation utilisés de nos jours (Java, C++, Ruby, etc.), cependant cela ne le rend pas plus compliqué, bien au contraire. L'Objective-C est fait pour être lu et compris directement par le programmeur. Par exemple pour faire une comparaison entre deux chaînes de caractères en C vous devriez faire :

 
Sélectionnez

strcmp(‘maChaine', ‘maChainedeComparaison')
				

En Objective-C, la syntaxe sera différente :

 
Sélectionnez

[maChaine isEqualToString:@”maChainedeComparaison”]				
				

À noter :
- l'Objective-C étant un « dérivé » du C, vous pouvez coder aussi bien en Objective-C qu'en C, cependant vous devez entourer votre code avec des crochets pour que le compilateur inteprète votre code en tant qu'Objective-C et non en C ;
- lorsque vous utilisez une chaîne de caratères Objective-C, vous devez le « signaler » au compilateur en la précedant du signe @.

 
Sélectionnez

// Chaine C
myString = "Chaîne C";
// Chaine Objective-C
myString = @"Chaîne Objective-C";				
				

Les types

Comme nous venons de le préciser un peu plus haut, l'Objective-C est un « dérivé » du langage C, ce qui implique donc que l'Objective-C possède tous les types primitifs de C. Ainsi, vous aurez accès aux types suivants : int, char, short, long, etc.

Cependant, Objective-C arrive avec son lot de nouveaux types. Vous pourrez donc avoir des variables de type NSString pour une chaîne de caractères, NSArray pour stocker vos données dans un tableau, NSDictionary pour vos tableaux key/value. Notez qu'Objective-C introduit un type unique et très intéressant qui est le type « id » qui pourra être utilisé lorsque vous ne connaissez pas le type de votre variable/objet/paramètre.

À noter : sachez que chacun de ces types NS est statique, c'est-à-dire qu'une fois que vous avez attribué une valeur à votre objet, vous ne pourrez plus modifier sa valeur. Cependant, il existe un équivalent dynamique qui vous permettra de changer la valeur de votre objet à volonté en utilisant le mot clé « Mutable ». Par exemple, le type dynamique pour NSString sera NSMutableString, idem pour NSArray et NSDictionary qui seront NSMutableArray et NSMutableDictionary.

Les méthodes

Comme tout langage objet, vous avez deux types de méthodes en Objective-C : les méthodes de classe et les méthodes d'instance.

La déclaration d'une méthode en Objective-C se découpe en trois ou quatre parties :

  1. vous devez choisir ce que vous déclarez : soit une méthode de classe, soit une méthode d'instance. Les méthodes de classe seront précédées du signe « + », les méthodes d'instance par le signe « - » ;
  2. ensuite il vous faudra définir le type que votre méthode retournera entre parenthèses...
  3. ...suivi du nom de votre méthode. Essayez d'obéir aux conventions Objective-C en nommant vos méthodes pour qu'on puisse comprendre ce que cette dernière effectuera, et n'oubliez pas le camelCase (première lettre en minuscule (pour les noms des propriétés et méthodes) ou en majuscule (pour les noms de classe) et chaque nouveau mot avec la première lettre en majuscule). Par exemple une methode qui affiche l'heure sera : « afficherHeure » et non « methode1 » ou encore « AfficherHEURE » ;
  4. enfin, viendront se greffer les paramètres, s'il y en a, avec leur type précédé du signe « : ».

Facile non ? Sinon un exemple qui résume les quatre points vous aidera sans doute.

Déclaration d'une méthode dans le fichier header
Sélectionnez

// Déclaration d'une méthode d'instance qui retourne rien et qui prend deux
// paramètres : une propriété de type id et un nom de type NSString
- (void) changeProperty: (id *) property andName: (NSString *) name;
 
// Déclaration d'une méthode de classe sans paramètre
+ (void) myMethod;
				
Implémentation d'une méthode dans le fichier d'implémentation
Sélectionnez

// Implémentation de notre méthode d'instance qui retourne rien et qui prend
// deux paramètres : une propriété de type id et un nom de type NSString
- (void) changeProperty: (id *) property andName: (NSString *) name{
// Insérez ici votre code
}
 
// Déclaration de notre méthode de classe
+ (void) myMethod{
// Insérez ici votre code
};				
				

À noter : si vous souhaitez implémenter vos getters et setters différement, vous pouvez utiliser les mots-clés « @property » et « @synthesize », cela vous fera gagner du temps et des lignes de code. Vous pourrez par la suite utiliser le « dot-syntax » pour changer ou récupérer la valeur de vos propriétés :

Avant
Sélectionnez

// Fichier .h
- (NSString *) name;
- (void) setName: (NSString *) n;
 
// Fichier .m
- (NSString *) name{
  return [self name];
}
- (void) setName: (NSString *) n{
  // problème de mémoire ici mais nous verrons dans la suite
  name = n;
}
 
//Appel de la propriété
[object name];				
				
Après
Sélectionnez

// Fichier .h
@property (nonatomic, retain) NSString* name;
 
// Fichier .m
@synthesize name;
 
//Appel de la propriété
object.name;
				

La gestion de la mémoire

Voici la partie qui peut causer pas mal de maux de tête, je vous demanderais donc d'être très attentif car la gestion de la mémoire joue un rôle très important dans le développement de votre application iPhone. C'est ce qui va d'ailleurs faire la différence entre une application fluide et une application qui ne fait que crasher.

Contrairement au développement sur Mac, ou encore au développement Java, Cocoa Touch ne vient pas avec un Garbage Collector se chargeant de gérer la mémoire automatiquement. En effet, un Garbage Collector demande beaucoup de ressources, or nous sommes sur un mobile où il y a peu de ressources disponibles contrairement à un ordinateur de bureau. Apple a donc decidé de ne pas intégrer un tel système afin d'économiser des ressources système.

Lorsque vous aurez une variable à déclarer, il vous faudra d'abord lui allouer un espace dans la mémoire du téléphone. Lorsque vous aurez cet espace qui vous sera alloué, il vous faudra ensuite initialiser cet objet si vous souhaitez l'utiliser. Attention, vous devrez toujours utiliser des pointeurs lorsque vous déclarez vos variables qui auront besoin d'un espace mémoire (autres que types primitifs). Ensuite vous pourrez utiliser toutes vos méthodes d'instance pour effectuer vos actions. Lorsque vous aurez fini avec votre objet, il ne vous restera qu'à le « libérer » de la mémoire du téléphone.

Pour récapituler :

  • on alloue un espace mémoire à notre variable :
 
Sélectionnez

NSString * myString = [NSString alloc];						
				
  • on initialise notre variable afin de pourvoir appeler les méthodes qui nous intéressent :
 
Sélectionnez

myString = [NSString init];						
				
  • on appelle une méthode pour changer le texte de notre string par exemple :
 
Sélectionnez

// Ici on ajoute un @ devant notre chaîne de caractère pour signaler
// qu'on utilise une chaîne Objective-C et non C.
[myString setText:@"HelloWorld"];						
				
  • enfin lorsqu'on a fini avec notre objet on le libère :
 
Sélectionnez

// Le mot clé release permet de décrémenter le retainCount
[NSString release];						
				

À noter : en général, le release se fera dans la méthode dealloc de votre objet, en effet, chaque objet héritant de la classe mère « NSObject » possède une méthode « dealloc » dans laquelle nous libérerons tous les objets que nous aurons créés précédemment.

Voici à quoi ressemblera votre méthode d'instance « dealloc » :

 
Sélectionnez

- (void)dealloc {
  [maPropriété release];
  [super dealloc];
}		
				

Comme vous avez pu le lire, le mot clé « release » ne libère pas vraiment notre objet. Il faut savoir que dès qu'on alloue un espace mémoire à un objet, le retainCount de cet objet se voit incrémenté. Ce retainCount supérieur à 1 permet à l'objet de rester en vie. Ainsi, vous avez la possibilité d'incrémenter ce retainCount grâce au mot clé « retain », ou de le décrémenter grâce au mot clé « release ».

Dès que le retainCount est égal à 0, le système se charge de « libérer » l'espace mémoire occupé précédemment par l'objet en question.

Vous avez également la possibilité d'utiliser la mot clé « autorelease » qui effectue la même action que « release » sauf que ceci se produira plus tard dans le temps. Sachez qu'en permanence, lorsque votre programme est lancé, une boucle tourne en tâche de fond qui s'occupe par exemple de récupérer les événements extérieurs tels qu'un appui sur l'écran de l'iPhone, ou encore d'effectuer l'action autorelease sur un objet lors du prochain passage de la boucle. On parle ici de millisecondes.

À retenir

 
Sélectionnez

// alloue un espace mémoire + initialise l'objet
NSString * myObject = [[NSString alloc] init]  // retainCount = 1
 
// augmente de retainCount de + 1
[myObject retain]; //retainCount = 2
 
// on diminue le retainCount de -1 et encore de -1
// ce qui a comme effet de libérer notre objet
[[myObject release] release]; // retainCount = 0				
				

À noter : il ne faut jamais appeler la méthode release sur un objet dont vous n'avez pas le contrôle. En effet, vous devez appeler la méthode release seulement sur les objets qui vous appartiennent, c'est-à-dire ceux que vous avez créés.

Récapitulatif

Pfiou, on en voit presque le bout. Avant de passer au développement de notre toute première application iPhone dans le prochain tuto, nous allons récapituler tout ce que nous venons de voir à travers une classe Voiture qui aura deux attributs (marque et couleur) et une méthode d'initialisation qui definira la marque et la couleur de la voiture.

Fichier : header/interface // Voiture.h
Sélectionnez

#import <Cocoa/Cocoa.h>
@interface Voiture : NSObject {
NSString * couleur;
NSString * marque;
}
// Getters et setters
@property (nonatomic, retain) NSString* couleur;
@property (nonatomic, retain) NSString* marque;
end				
				
Fichier implementation // Voiture.m
Sélectionnez

#import <Voiture.h>
@implementation Voiture
 
- (id) initWithColor: NSString* color andMarque: NSString* model
{
// Ici on instancie notre classe grâce à notre classe NSObject
// et on vérifie si l'instanciation s'est bien déroulée
  if (self = [super init])
 {
    self.couleur = color;
    self.marque = model;
  }
}
 
@synthesize couleur;
@synthesize marque;
 
- (void) dealloc
{
  [couleur release];
  [marque release];
  [super dealloc];
}
end
				

Utilisation de notre classe :

 
Sélectionnez

//retainCount = 1
Voiture * mercedes = [[Voiture alloc] initWithColor:@"gris" andMarque:@"Mercedes"];
// ....
[mercedes release]; // reteainCount = 0 ce qui apelle la méthode dealloc				
				

Voilà c'est terminé pour ce second tutoriel iPhone. Rendez-vous très vite pour le prochain tutoriels qui vous permettra de réaliser votre première application qui sera un classique mais efficace Hello World.

II. Remerciements

Je tiens à remercier tout particulièrement Emré Ozdemir qui a rédigé tout ce tutoriel.
Merci également à eusebe19 d'avoir pris le temps de relire et de corriger ce tutoriel.

III. Liens