II. Définir les attributs d'une classe▲
Les variables présentent l'état d'un objet. On les appelle propriétés, attributs, données membres. Cocoa retiendra plutôt le terme propriété alors que Java réserve ce terme aux attributs des Java Beans.
Un objet fournit un jeu de services, mais pour pouvoir être implémentés ces services dépendent de l'état courant de l'objet.
C'est le rôle des attributs d'un objet que de définir son état à un instant donné.
Nous allons donc voir ici comment nous allons définir les attributs de nos objets Objective-C.
Pour rappel, il est important clarifier ce qu'est une variable. Une variable n'est qu'une étiquette qui est rattachée à une valeur.
Un objet peut manipuler des variables d'instance et de classe :
- les variables de classe ont une valeur définie dans la classe ;
- les variables d'instance ont une valeur définie dans l'objet.
Le schéma suivant représente cette structure :
On y voit clairement que si chaque instance partage le même jeu de noms de variables, ces variables ont toutes des valeurs différentes.
Au contraire, les variables de classe ont une valeur unique partagée entre toutes les instances de la classe.
II-A. Déclarer des variables d'instance▲
Les variables sont déclarées dans l'interface de la classe.
@interface
MaClasse {
// Déclaration des variables d'instance entre
// les accolades
}
...
La syntaxe est celle des déclarations C normales. Pour plus de détails, je vous renvoie donc à la documentation de référence disponible sur le site Apple ou dans votre installation de XCode.
Notre classe SimpleClass va définir deux attributs :
- un identifiant vers un objet destination ;
- un nombre indiquant une limite de vitesse.
@interface
SimpleClass : NSObject
{
id
destination;
int
speedLimit;
}
En Objective-C, contrairement à Java, il est obligatoire d'utiliser explicitement la syntaxe C des pointeurs lorsqu'on déclare une variable de type objet.
(
TYPE) *
variable;
La seule exception étant l'utilisation du type id qui est implicitement un pointeur sur un type quelconque d'objet : un équivalent du void *, mais restreint aux objets.
En effet, comme nous le verrons en parlant du cycle de vie des objets, l'initialisation suivante n'est pas valide puisque les méthodes alloc et init retournent toutes deux un id qui est un type pointeur sur objet.
// Définition invalide
NSString
chaine =
[[NSString
alloc] init];
Seule l'expression suivante permet de construire une chaîne :
// Définition correcte
NSString
*
chaine =
[[NSString
alloc] init];
II-B. Et les variables de classe ?▲
Pour un développeur Java, les attributs d'une classe se divisent en deux groupes :
- les attributs des instances de la classe : chaque instance de la classe partage le même ensemble de variables, mais chaque instance leur associe des valeurs distinctes ;
- les attributs de la classe : les attributs de classe sont partagés entre toutes les instances de la classe.
C'est le modèle classique présenté au début de cet article.
En Objective-C les variables de classe n'existent pas. Elles sont en fait inutiles, car le langage C permet d'obtenir la même fonction par l'utilisation de variables privées dans un module.
Capable de posséder ses propres variables et sa propre portée, le fichier module joue le rôle de conteneur que la classe joue en Java.
Pour illustrer ce concept, nous allons créer une nouvelle classe ClasseAvecVariable dont l'interface est la suivante :
@interface
ClasseAvecVariable : NSObject
{
@private
int
index;
}
/* ... */
@end
La variable de classe n'est pas définie dans l'interface. Elle ne le sera que par les méthodes de classe pour y accéder.
Dans l'implémentation nous déclarons la variable de classe comme une variable globale, mais dont la portée est restreinte au fichier source courant.
#
import
"ClasseAvecVariable.h"
static
int
compteur =
100
; // Variable privée au module
@implementation
ClasseAvecVariable
/* ... */
@end
Nous remarquerons que la variable étant d'un type simple nous pouvons combiner en une seule ligne la déclaration et la définition de la variable.
Pour les objets, il est possible de les initialiser avec une méthode d'initialisation de la classe. Ce sujet sera traité avec le cycle de vie des objets.
Cette même classe pourrait être définie de façon plus concise en Java comme suit :
public
class
ClasseAvecVariable {
private
static
int
compteur =
100
; // Variable de classe
private
int
index; // Variable d'instance
// ...
}
Il est tout de même important de remarquer que si l'utilisation de variables privée à un module semble similaire à une variable de classe, nous n'avons pas vraiment une stricte équivalence avec Java.
- Comme en Java une variable de classe si elle est surchargée, elle n'en est pas pour autant capable de polymorphisme.
- Contrairement au Java, une variable de classe est systématiquement privée. Les variables de classe ne sont ni protégées ni publiques. Une classe peut cependant être associée à des variables globales publiques déclarées dans son fichier en-tête et définies dans le module d'implémentation.
Il est possible de restreindre la visibilité d'une variable externe à un module, mais cela implique de définir un fichier en-tête spécifique et complique peut-être inutilement le code.
Variable de classe |
Java |
Objective-C |
---|---|---|
Déclaration |
Source Java |
Fichier en-tête |
Visibilité |
Publique, protégée, ou privée |
Privée |
Syntaxe |
static TYPE var ; |
static TYPE var ; |
II-C. Visibilité des attributs▲
En Java, mais aussi en Objective-C, les variables de classe peuvent profiter de trois niveaux de visibilité :
- Privée, la variable n'est visible que dans la classe qui la déclare ;
- Protégée, la variable est visible dans la classe qui la déclare ainsi que dans ses classes dérivées ;
- Publique, la variable est visible à partir de toute partie de code.
Java et Objective-C définissent la visibilité d'une variable membre différemment :
- Java définit la visibilité pour chaque variable en ajoutant un qualificatif de portée à la déclaration ;
- Objective-C définit des sections dans la déclaration des variables, chaque section définit le niveau de portée des variables qui y seront déclarées.
En cela, Objective-C ressemble d'avantage à C + + qu'à Java.
Les mots clefs utilisés sont similaires.
Portée |
Java |
Objective-C |
---|---|---|
Privée |
private |
@private |
Protégée |
protected |
@protected |
Publique |
public |
@public |
II-D. Utilisation des attributs▲
Dans une méthode de la classe, les attributs sont accessibles comme des variables normales. Elles sont dans la portée de la classe et à ce titre sont directement accessibles.
Nous pourrions donc écrire la méthode suivante pour la classe SimpleClass :
(
id
) init {
[super
init];
destination =
location;
speedLimit =
limit;
return
self
;
}
Si l'on n'est pas dans la portée de la classe, par exemple lorsqu'on accède à une variable publique, il faut utiliser la notation classique du C pour accéder à une valeur d'un type structuré. Les objets étant déclarés par des pointeurs sur le type, c'est l'opérateur flèche d'indirection de pointeur qui sera utilisé :
MaClasse *
objet;
// ...
objet->
variable =
valeur;
II-E. Pour finir▲
Nous sommes maintenant capables d'ajouter des données à nos objets en leur associant des variables d'instance ou de classe.
Mais nos classes resteront inertes tant qu'elles ne proposeront pas des services. Ces services sont fournis par l'intermédiaire de méthodes répondant à des messages. C'est le sujet de la Objective-C.