Les bases de l'Objective-C

Axon de Tuto Mobile

Bonjour à tous, dans ce second tutoriel iPhone, nous allons découvrir les bases du développement sur iPhone/iPad. Cette partie nous permettra de nous familiariser avec l'Objective-C et les outils de développement fournis par Apple (Xcode dans un premier temps).

N'hésitez pas à nous faire part de votre avis sur cet article : Commentez

- Titre : Les bases de l'Objective-C

- Auteur : Axon de Tuto Mobile

- Parution : 9 février 2011

- Mise à jour : 27 juin 2020

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2011 RENOUARD. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

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

- Comment créer une classe ?

- La syntaxe

- Les types

- Les méthodes

- La gestion de la mémoire

- À retenir

- Récapitulatif

- II. Remerciements

- III. Liens

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 :

@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 :

// 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 :

strcmp('maChaine', 'maChainedeComparaison')

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

[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 interprète votre code en tant qu'Objective-C et non en C ;

- lorsque vous utilisez une chaîne de caractères Objective-C, vous devez le « signaler » au compilateur en la précédant du signe @.

// 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 méthode 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

// Déclaration d'une méthode d'instance qui ne 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

// Implémentation de notre méthode d'instance qui ne 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éremment, 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

// 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

// 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 demanderai 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 décidé 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 :

NSString * myString = [NSString alloc];

- on initialise notre variable afin de pouvoir appeler les méthodes qui nous intéressent :

myString = [NSString init];

- on appelle une méthode pour changer le texte de notre string par exemple :

// 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 :

// 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 » :

- (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 le 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

// 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 définira la marque et la couleur de la voiture.

Fichier : header/interface // Voiture.h

#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

#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 :

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

Voilà c'est terminé pour ce second tutoriel iPhone. Rendez-vous très vite pour le prochain tutoriel 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

Tutoriel original sur Tuto Mobile