

La Programmation : Le Langage Objective-C (1)
La Programmation : Le Langage Objective-C (1)
Sujets abordés :
- Introduction à la POO
- Définition d'une classe
@interface @implementation
- Définition des méthodes
Modifications apportées au 06/12/2006 :
- Méthode "
dealloc " redéfinie + text explicatif modifié - Méthode "
setNumTel: " redéfinie + text explicatif modifié
Bienvenue à tous ! Voici, le début, à proprement parlé, du tutoriel sur la programmation Mac. Ce tutoriel risque, à mon avis, de faire partie des épreuves inventés par François Pérusse... Le Çarisquedettlon ! Et oui car l'Objective-C, en tout objéctivité () est un langage assez volumineux, mais surtout très puissant. Ce que je trouve dommage c'est que ce langage ne soit utilisé que sous Mac, et particulièrement avec l'API Cocoa. C'est un langage assez stricte, mais assez clair dans l'ensemble car très bien compartimenté, contrairement à ses cousins (Java et C++), je m'expliquerai sur ce point
. Enfin bon, de toutes façons, nous sommes Mac ici, donc nous l'étudierons pour Mac
, même si il est utilisable sous d'autres systèmes grâce à GCC.
Dans ce cours je procèderai un peu bizarrement, je vais vous plonger d'un seul coup dans la création de classes et vous indiquer pas à pas comment procéder pour la création et l'utilisation des classes. En vous indiquant les différentes procédures et techniques je vous parlerai des nouveaux concepts qu'on verra au fur et à mesure. J'espère que vous connaissez assez bien le C car, comme ce langage est réellement un sur-ensemble du C, il ne sera pas rare que je fasse des parallèles entre els deux langages, voire même que j'utilise du C pur avec de l'Objective-C pur (oui oui c'est possible ). Donc... À vos cerveaux et prennez votre courage à deux mains !

Introduction
Un peu d'Histoire
L'Objective-C est né dans les années 80 pour commencer par Brad Cox et Tom Love (dans leur compagnie Stepstone) qui ne lui doivent pas tellement leur notoriété... (Personnellement, je n'ai jamais vu leurs noms autre part ). Ce langage, aussi puissant qu'il soit, n'a été popularisé qu'en 1988 grâce à notre iPapy international ! Et oui, Steve Jobs, avec son entreprise NeXT, a racheté la license de l'Objective-C et a créé sa propre version de compilateur et ses propres bibliothèques, celles-ci, vous le verrez plus tard, portent toutes les initiales NS au début de leur nom... NS pour NeXTStep, l'interface utilisateur qui se base sur ces bibliothèques. Donc Steve Jobs en revenant chez Apple n'a pas renié son deuxième petit bébé NeXT
et il le fait vivre à travers ce langage.
La Programmation Orientée-Objet (POO)
Les années 80 ont vu la naissance d'une toute nouvelle génération de langage de programmation, les Langages Orientés Objet. Avant cela la pogrammation était uniquement procédurale, et toutes les fonctions étaient partagées globalement par le programme, bien que certaines fonctions ne s'occupaient que de certaines structures, il n'en reste pas moins que tout le programme pouvait les utiliser. La POO a cherché à éliminer ce problème, au lieu de voir le programme dans son ensemble avec ses fonctions, ses types balancés comme ça, on a cherché à voir le programme comme un ensemble d'Objets. Il s'agit en fait de structures comme on peut voir en C, par exemple une structure nommée Rectangle qui contient 2 variables Longueur et Largeur, mais auxquelles on assigne des fonctions spécifiques qui ne pourront être utilisées que pour cette structure uniquement (--> Référez-vous au tutoriel sur le C du site du Zéro <--).
En fait, en POO, on ne parle pas de Structure, mais de Classe et d'Objet, on ne parle pas non plus de fonctions, mais de Méthode. La POO se base sur des concepts plutôt nouveaux pour l'époque : la réutilisabilité du code et l'encapsulation des données.
Imaginez un instant que vous deviez construire une maison... Mais qu'au lieu de pouvoir acheter le ciment, le bois de charpente, etc. Vous deviez vous-même mélanger du sable à del'eau et tailler vous-même les arbres pour faire vos poutres... C'est sûr, ça peut être valorisant, mais c'est extrêmement long et harassant. Et bien dites-vous qu'avant la POO, la programmation c'était ça ! Reconstruire toutes les briques une-à-une pour arriver à faire quelque chose de potable. C'est là que la POO est arrivée pour sauver les développeurs !
Alors déjà, la réutilisabilité est importante, en fait ça signifie que lorsqu'on a fait une brique on peut la dupliquer à l'infinie selon nos besoins. On réutilise une structure bien faite sans avoir à tout redéfinir à nos risques et périles. L'exemple le plus concret en C, ce sont les chaînes de caractères. Pour ceux qui connaissent le langage (si vous n'y connaissez rien ça sert rien de continuer ), une chaîne de caractère est en fait un tableau de char (char* ou char[]), l'utilisation d'une telle structure est assez dangereuse du point de vu des dépassements, mais aussi peu pratique puisqu'il faut gérer caractère par caractère..., alors que dans les langages qui héritent du C, on a une classe chaîne prédéfinie. Chez Java et C++ ça s'appelle String, et sous Objective-C, on a la classe NSString, ces classes gèrent à la fois le redimensionnement de la chaîne, son nombre de caractères, etc. Bien plus pratique, on a plus besoin de s'embêter avec des pointeurs sur char, en tout cas pour les chaînes.
Ensuite l'encapsulation des données, LE concept de base de la POO. Je vous ai dit que les classes ressemblent aux structures C, à la différence près qu'en C, les variables contenues dans la structure sont laissées en pâtures à tout le programme, c'est-à-dire que n'importe quelle fonction peut modifier le contenu des variables et rendre la structure incohérente ! L'encapsulation permet en fait de cacher, aux "individus" extérieurs à la classe, la structure même de l'objet, ainsi que son contenu. Il n'est plus question de toucher aux données directement !! Ah ça non !! Trop dangereux ! Imaginez seulement qu'un objet Personne se retrouve avec un âge négatif à cause d'une mauvaise manipulation de l'utilisateur !
Alors voici la représentation communément acceptée d'un objet :
Vous remarquez que les données (data) sont complètement entourées de méthodes (method), il est impossible d'y toucher directement, ce sont les méthodes qui manipulent ces données. Cela permet, comme je l'ai dit plus haut, de conserver la cohérence d'un objet par rapport à son implémentation. Toute la programmation objet se basera là-dessus, la gestion de données internes par des méthodes et la "discussion" entre les objets par ces méthodes.
Autres concepts apparus avec la POO, c'est la gestion des Exceptions. Elles représentent tous les cas particulier et inévitable d'une exécution, la plus connue étant la division par Zéro, c'est quelque chose d'interdit mais il faut être capable de gérer ce problème. Avant ce concept, les erreurs étaient gérer par la fonction qui la générait... Alors, soit votre programme plantait, soit vous aviez un retournement d'erreur. Les exceptions permettent aux fonctions de déléguer leur gestion aux méthodes et programmes qui appellent la fonction/méthode responsable de l'exception. La méthode "essaye" (try) d'exécuter une autre méthode avec certain paramètre et, si besoin est, attrappe (catch) une exception qu'elle gèrera en conséquence... Soit en retournant un message d'erreur, soit en lançant d'autres instructions. Cela devient bien plus pratique à programmer et ça permet d'éviter les mauvaises surprises.
Vous avez aussi d'autres notions que je préfère aborder plus tard, si vous avez intégré tout ça, c'est déjà pas mal.
Le Vif du sujet : Objective-C
Alors, ça c'était une introduction à la programmation objet, ces concepts sont plus ou moins partagés par les autres langages de programmation. On va maintenant s'atteler à la POO en Objective-C. Le C, n'est pas le seul parent de l'Objective-C, il hérite une partie de son implémentation de Small-Talk, probablement le premier langage de POO de l'histoire. Il hérite surtout dans sa gestion des méthodes qui ne ressemblent pas du tout aux fonctions C.
En effet, si le C++ est un C amélioré, donc modifié, avec la POO en plus, et que le Java est un héritié du C en n'étant plus du tout compatible avec... L'Objective-C est un véritable sur-ensemble du C, c'est-à-dire qu'il intègre complètement le C sans en modifier une seule ligne, sans même utiliser ses structures à son profit ! Non, l'ObjC a ajouté les concepts de la POO aux C en trouvant des structures, des implémentations totalement différentes de celles du C, ce qui permet en fait de ne pas se mélanger les pinceaux. Une méthode ne peut être confondue avec une fonction, de même qu'une classe ou un objet ne peuvent être confondus avec un type. Je ne m'en suis pas rendu compte au départ, mais c'est finalement très agréable ! Cela facilite les corrections et la relecture.
Préparation
Avant que j'entame le cours en tant que tel, on va créer un nouveau projet Xcode pour faire de la programmation en Objective-C, car il nous fait pratiquement tout . Commencez par créer un nouveau projet (Pomme + Shift + N) de la famille : Command Line Utility et de type Foundation Tool. Alors, vous voyez votre fenêtre de projet normale, vous remarquez la présence d'un fichier portant le même nom que votre projet, c'est l'équivalent du fichier "main" en C et a la même fonction : définir le point d'entrer de l'application, il porte aussi l'extension : ".m", c'est l'extension des fichiers sources en Objective-C, j'y reviendrai. Alors comme d'habitude, pour tous les projets de type ligne de commande (Command Line), Xcode génère un "Hello, World!", le petit progrmame qui vous affiche "Hello, World!" dans la console. Vous pouvez tester si vous voulez. Ici, on utilise la fonction C NSLog() définit dans la framework "Foundation" de Cocoa et qui affiche une chaîne de caractères sur un terminal. Vous pouvez aussi remarquer la présence d'expressions entre crochets "[ ]", ce sont des messages Objective-C... Nous allons voir ce que sont ces messages maintenant.
Des classes, des objets, des méthodes, des messages, de l'Objective-C quoi !
Héhé, quels sont tous ces termes ??? Trois d'entre-eux (c'est-à-dire tous sauf message), sont communs à tous les langages objets, voici des petites définitions :
- Classe : la classe est une structure de données, elle définit un ensemble de données encapsulées, que l'on nomme attributs, et un ensemble de méthode qui permettent d'agir sur ces attributs, par exemple : la classe Disque, elle a pour attribut "Nom du disque", "Nom de l'artiste", "nom des chansons", et comme méthodes elles possèdent "modifier le nom du disque"...
- Objet : un objet est une INSTANCE de classe : prennez par exemple la classe Disque, vous avez sa définition : la Classe, juste au-dessus, et bien un objet de cette classe c'est par exemple le disque qui a comme "nom du disque" : "Reise, Reise" et comme "nom d'artiste" : "Rammstein", et quelques chansons. Si beaucoup de tutoriel confondront la ntion d'objet et de classe (et moi avec), ces deux notions sont différentes, en effet, dans notre exemple : un de nos objets de la classe disque a pour attribut "Reise, Reise", et pourtant nous pouvons avoir un autre objet Disque qui a pour attribut "American Idiot", ce sont deux instances de la classe Disque, c'est-à-dire qu'elle partage la même structure et les mêmes méthodes, mais pas les mêmes valeurs d'attributs.
- Autre exemple : Par exemple chez moi j'ai 4 chats... Imaginons la classe Chat, alors ses attributs sont :
- Nom
- Sexe
- Couleur
- etc.
Et donc chez moi, j'ai 4 "instances" de cette classe, 4 objets avec des valeurs d'attributs différents :- Baghera, mâle, noir...
- Ashoka, femelle, gris
- Boulawane, mâle, noir et blanc
- Luna, femelle, tigrée
Donc mes 4 chats, sont bien des chats, c'est-à-dire des instances de la classe "Chat", mais chacun d'eux sont des "objets" (je ne veux pas de problème avec la SPA, j'adore mes chats !!!) différents, avec des noms différents, des couleurs différentes, etc.
Une classe définie donc un plan, et les objets sont des reproductions de ce plan avec des valeurs différentes. - Autre exemple : Par exemple chez moi j'ai 4 chats... Imaginons la classe Chat, alors ses attributs sont :
- Méthode : indivisibilité d'une classe, elles permettent la gestion des données / attributs de la classe à laquelle elles apprtiennent.
- Message : alors ce terme existe bien que je conteste (personnellement) son utilité véritable, c'est juste histoire de noyer le poisson. En fait,en ObjC, on exécute pas la méthode d'un objet, on envoie un "message" à un objet qui exécutera la méthode... C'est une petite subtilité de vocabulaire, c'est juste pour montrer le dynamisme du langage... Bah oui, si vous exécutez directement la méthode c'est quelque chose de prédéfini, alors que si vous envoyer un message c'est quelque chose de plus hasardeux. Enfin, c'est une subtilité un peu inutile puisqu'il n'est pas possible à proprement parler d'exécuter une méthode. Donc il faut savoir qu'on discute avec un objet à l'aide de messages. Mais au final ça revient à exécuter une méthode :P.
Les Classes
On va enfin pouvoir commencer la programmation objet ! Ah Ah !
Pour ceux qui ont déjà fait du C++, vous comprendrez un peu mieux. Mais pour ceux qui ont déjà fait de la programmation modulaire en C, en utilisant les fichier ".c" et ".h" correspondant cela devrait être plus facile à comprendre.
La définition d'une classe, j'entends par là sa déclaration (déclaration de la structure générale : attributs et méthodes de la classe) et son implémentation (la définition du déroulement des méthodes), nécessite 2 fichiers, un fichier d'en-tête (ou header) en ".h" et un fichier source Objective-C avec l'extension ".m". Donc, on va retourner dans Xcode.
Voici les icônes des fichiers ".m" et ".h" sous Xcode (elles sont belles hein??? :P) :


Ainsi, une classe aura toujours à son nom ces 2 types de fichiers.
Alors, comme on est sous Xcode, on va pas se priver de ses outils. On va créer une nouvelle classe Objective-C. Direction Menu "File" --> New FIle? (Pomme + N). Vous sélectionnez, dans la famille Cocoa, le type de fichier Objective-C Class. Vous donnez un nom à ce fichier, il deviendra le nom de votre classe, à cet égard il ne peut contenir que des caractères alphanumériques (Majuscules : A-Z, minuscules : a-z, chiffres : 0-9) et le caractère underscore "_". Un nom de classe comme toujours par une Majuscule (convention), et sûrement pas par un chiffre (obligation), si le nom de cette classe comporte plusieurs mots, il vaut mieux signifier la présence de ces mots en mettant des majuscules à chaque nouveau mot (exemple : ChatPersan, CompteBancaire), ou bien les séparer par des underscore. Vous pouvez aussi préfixé les noms de vos classes par vos initiales par exemple, comme le fait Apple (préfixe : NS), moi je peux par exemple préfixer mes noms de classes par Psy... Ce que je ne ferai pas parce que j'ai la flemme . Il ne faut surtout pas retirer l'extension ".m" du fichier.
Pour faire ce tutoriel on va prendre un exemple concret. On va créer une classe "Personnel" qui représentera les emloyés d'une entreprise. Veillez à ce que "Also create Personnel.h" soit coché.

Vous devirez voir apparaître les deux nouveaux fichiers dans l'arborescence de votre projet... Placez ces deux fichier sans le dossier/groupe de votre projet dans la barre de droite.
L'@interface d'une classe :

Cliquez sur le fichier Personnel.h pour visionner son contenu dans l'éditeur. Voici ce que vous devriez avoir :
Si vous êtes habitués au C, une première chose ne devrait pas vous échapper, c'est la directive de préprocesseur "
Sinon, vous risquez d'inclure plusieurs fois le même fichier ce qui peut poser des problèmes à la compilation. La directive "#import" vous dispense d'écrire ces lignes de codes très lourdes. Elle dit au compilateur d'intégrer le fichier si et seulement si il ne l'a pas déjà été.
Ensuite, on rencontre la déclaration de la classe aussi appelée interface de la classe. Elle est entourée de 2 mots clés "
Les Attributs :
Après cette ligne nous avons l'interface de la classe. À commencer par la déclaration des variables. En Objective-C, par définition et par défaut, toutes les variables d'instances, appelées aussi attributs, sont "protégés", c'est-à-dire qu'ils ne sont visibles que de l'intérieur de la classe ainsi que des classes qui héritent de celle-ci. Il est possible de modifier cette visibilité grâce aux mots clés suivants :
- @public : tous les attributs qui suivent jusqu'à l'accolade fermante ou un des autres mots clés qui suivent seront visibles de partout et par tous, c'est par définition à l'opposé du concept majeur de la POO : l'encapsulation, qui veut que les attributs soient invisibles et donc intouchables de l'extérieur. Ce n'est ) utiliser qu'en ultime recours !
- @protected (protégé) : les attributs qui suivent sont visibles par les objets de la classes et ceux qui héritent de la classe. C'est la valeur par défaut.
- @private (privé) : les attributs ne sont visibles que par les objets de la classe.
Ne vous en inquiétez pas, vous n'aurez pas à le sutiliser très très souvent, d'ailleurs je ne les utilise jamais. Je laisse la visibilité par défaut.
Toujours est-il qu'entre ces accolades se trouveront tous les attributs de notre classe. Ils se déclarent comme des variables toutes simples.
C'est-à-dire :
En objective-C, il n'est pas scandaleux de dire qu'une classe est aussi un type, par contre, si dans le cas des types génériques (type du C :
Donc ne venez pas vous plaindre que votre programme ne marche pas si vous m'avez oublié une étoile lors de la déclaration d'un objet, car si votre compilateur ne vous a pas crucifié c'est moi qui le ferai . Et ne vous avisez pas non plus d'oublier le point-virgule ";" à la fin de chaque déclaration !
Mais revenons à nos moutons. Pour l'instant, notre classe est rudimentaire, elle va avoir 3 attributs :
- numPers, de type entier, et qui contiendra le numéro du membre du personnel,
- nomPers, de type chaîne de caractères, qui contiendra le nom de la personne,
- numTel, de type chaîne et qui contiendra le numéro de téléphone, c'est une chîne parce qu'un entier ne peut pas commencer par zéro.
Le type chaîne est implémenté dans Cocoa, et il s'agit de NSString. Attention, c'est une chaîne fixée, c'est-à-dire qu'une fois attribuée elle n'est plus modifiable. Donc pour la modifier vous devez la supprimer et la réallouer.
Voici ce que cela devrait vous donner :
Vous remarquez la présence des étoiles à côter des NSString, donc ce sont bien des pointeurs. Et bien sûr les points-virgule ";" .
Les Méthodes :
On va maintenant déclarer les méthodes de cette classe. Ces déclarations se font après l'accolade fermante et avant le mot clé "
Il y a deux types de méthodes :
- Les méthodes de classe : leur déclaration commence par un "+", ces méthodes manipulent généralement des éléments commun à tous les objets, par exemple le nombre d'instances (objets) d'une classe X allouées en mémoire.
- Les méthodes d'instance : leur déclaration commence par un "-", ces méthodes manipulent les objets eux-mêmes, elles permettent de modifier un attribut, d'effectuer une certaine action, etc.
La déclaration des méthodes ne ressemblent pas du tout à celle du C. Déjà pour commencer, les déclarations commencent par le signe "+" ou le signe "-", ensuite le type renvoyé par la méthode se trouvent entre parethèses. Puis ensuite vient le nom de la méthode, si la méthode ne comporte aucun paramètre d'entrée (pour accéder à un attribut par exemple), le nom de la méthode est immédiatement suivit du point-virgule, sans parenthèse. Si la Méthode prend des paramètres, leur type, entre parenthèses aussi, et leur nom sont précédés de deux point ":". Exemple :
- Méthode de classe avec paramètres :
+ ( int ) maMethodePrendUneChaine: (NSString*) chaine etUnEntier: (int ) nombre; - Méthode de classe sans paramètre :
+ ( void ) monAutreMethode; - Méthode d'instance avec paramètres :
- ( id ) initialiseAvecNom: (NSString*) nom; - Méthode d'instance sans paramètre :
- (NSString*) nom;
Ce genre de déclaration est surprenant n'est-ce pas??? Déjà vous pouvez remarquer qu'à chaque nouveau paramètre vous devez ajouter un ":" précédé ou non de sa signification. En effet, je pourrais très bien définir une fonction f prennant 3 paramètres de cette façon : "- (float) f: (float): (float): (float)", mais qui comprendrait ce qu'elle fait ? Alors voilà les conventions :
- Les caractères admis dans les noms des fonctions sont toujours les mêmes : A-Z, a-z, 0-9 et "_", pas de caractères accentués et autres caractères spéciaux !
- Un nom de fonction commence par une minuscule, sûrement pas par un chiffre mais au milieu du nom pas de problème,
- Chaque nouveau mot porte une majuscule,
- On nomme chaque paramètre dans la déclaration, même si c'est inutile, pour permettre la compréhension,
- On écrit des phrases, généralement en anglais, pour indiquer ce que fais la fonction et chaque paramètre,
- Pour les méthodes renvoyant des attributs d'instance ou de classe, on donne le nom de l'attribut à la fonction. En ce qui concerne les méthodes qui renvoient un booléen (
BOOL ), c'est-à-dire vrai ou faux (YES ouNO en Objective-C), leur nom se compose de l'adjective précédé de "is" (est), exemple "isSelectable " (estSelectionnable) - Les méthodes modifiant un attribut commencent par "set" (attribuer/modifier) suivit du nom de l'attribut, exemple : "setSelectable:".
Ceux qui connaissent le C++ doivent se demander si la surcharge des méthodes est possibles. La surcharge est la possibilité de donnée à deux fonctions/méthodes différentes le même nom, elles seront alors différentes, pour le compilateur, par le nombre et les types des paramètres qu'elles récupèrent. Le compilateur gère ça en créant des étiquettes, à chaque méthode elle attribue une étiquette qui indique le nom de la méthode, le nombre de paramètre, les types de paramètres et leur ordre. En Objective-C la surcharge n'existe pas ! D'ailleurs c'est vous qui définissez les étiquettes, il s'agit en fait de leur nom complet, les deux points compris, par exemple, ma méthode de classe de tout à l'heure a pour étiquette et nom : "
Je reviens toujours un peu au C++ car il a l'avantage de posséder pratiquement tous les concept possibles et imaginables en POO. Nous allons voir quelles méthodes implémenter dans notre classe. En C++, toute classe possède ce qu'on appelle un constructeur (au moins un), c'est une méthode qui est appelé dès l'instanciation de l'objet et qui initialise celui-ci en lui attribuant un espace mémoire. Sur Objective-C cela s'appelle l'initialisation et ça se fait en deux étapes : Allocation de l'espace mémoire puis Initialisation des attributs. Ces deux étapes nécessites chacune une méthode distincte, et sur ces deux méthodes l'une d'elle doit obligatoirement être redéfinie par le développeur (vous), il s'agit de l'initialisation, il faut noter qu'il est aussi courant de définir une méthode (de classe généralement) qui fait les deux étapes elle-même. Ces méthodes renvoient toujours un (id) qui est le type objet par défaut (il s'agit d'un pointeur sur un objet ). Leur nom commence généralement par "init", elles peuvent ou non prendre des paramètres.
En C++, nous avons aussi un destructeur unique par classe, ce genre de méthodes, pas toujours nécessaire selon les attributs de la classe, est appelé lors du déréférencement de votre objet et permet de vider l'espace mémoire, utilisé par celui-ci, correctement. En Objective-C, cette méthode existe et est aussi obligatoire, sauf dans le cas d'une méthode n'étant pas destinée à être instanciée, auquel cas la méthode d'initialisation est aussi inutile. Elle porte le nom de "dealloc" (désalouer, sous entendu la mémoire utilisée par l'objet), c'est une méthode d'instance et elle retourne un (id), vous pouvez aussi ne pas mettre de valeur de retour, le compilateur comprendra quand même... Pour lui le type retourné par défaut des méthodes est le type (id).
Maintenant que tout est dit sur les deux méthodes nécessaires, nous allons implémentés les déclarations de nos méthodes, voici une liste non-exhaustive des méthodes, si vous pensez qu'il en faudrait plus, vous pouvez y aller :
Vous pouvez remarquer qu'il y en a un certain nombre . Et encore, j'ai supprimé une méthode dont on n'a pas encore l'utilité pour l'instant.
- Partie Modifiée : la méthode "
Enfin, voilà pour l'interface ! Tant de texte pour si peu de code écrit ! Ne vous inquiétez pas, vous allez pouvoir taper du code après, lors de la définition de l'implémentation des méthodes. Donc en conclusion, l'interface d'une classe définit les attributs de celle-ci ainsi que le nom de ses méthodes avec leur paramètre et type retourné.
Les Messages ou "Parlez-vous Objective-C ?"
Héhé ! Question Vocabulaire, l'ObjC est innovant, puisque pour les objets n'appellent pas des méthodes d'aures objets, non non non ! Ils s'envoient des "messages" ! C'est amusant puisque ça permet de voir les objets comme des entités totalement indépendantes, l'un n'est pas l'esclave de l'autre, et ces objets discutent entre eux, s'entre-aide en quelque sorte, on peut y voir là l'extension du concept de la communication inter-processus d'Unix qui a du plaire à Steve Jobs , c'est-à-dire une architecture horizontale, tous au même niveau pour atteindre un seul but !
Enfin en tout cas, c'est comme ça que je vois ce concept de messgaes, qui n'a pas d'autres intérêts, à mon avis, de dépeindre cette vision. Et oui puisque maintenant les données sont encapsulées, et donc inaccessibles de l'extérieur, il faut, pour arriver à fonctionner, faire communiquer tous ces objets. Alors les messages ont une syntaxe spéciale, vous avez déjà pu l'entrevoir plus tôt, rien qu'avec le programme "Hello, World!" offert par Xcode.
Voici la syntaxe :
Alors, le "receveur" est l'objet ou la classe, car il est possible d'envoyer des messages à des classes, qui doit recevoir le "message". Et le message, c'est en fait la méthode que vous souhaitez appeler avec les valeurs de ses paramètres. Alors, on va reprendre les méthodes de notre classe et voir des exemple de message et leurs utilisations dans un programme :
Par exemple, je veux connaître le numéro de personnel de l'objet : "Personnel *toto;", alors je vous rappelle la méthode rrenvoie un entier... Donc ce petit texte entre crochet sera "égal" à cette valeur, voici un petit code qui récupère le numéro de Personnel :
Alors là, vous voyez, "toto" est bien un pointeur sur un Personnel, mais cette étoile n'est nécessaire qu'à la déclaration ou dans la déclaration des paramètres des méthodes. C'es tun pointeur qui doit se trouver en tant que receveur ! Et à côté le message, qui ressemble étrangement à notre méthode de tout à l'heure...
Maintenant regardons une méthode avec des paramètres, je veux changer le numéro de téléphone de "toto" :
Alors, on voit déjà deux trucs, cette méthode ne renvoie rien (
Il est possible d'encapsuler dans un message dans un autre, c'est possible pour les méthodes qui renvoient quelque chose, c'est même très souvent utiliser, surotut lors de l'initialisation des nouveaux objets. Par exemple, on va initialiser notre "toto" à l'aide de notre méthode "init", voici la technique la plus usité et surtout celle que je vous conseille largement d'utilisé car elle permet d'éviter des erreurs :
Alors là, vous voyez beaucoup de choses en une seule ligne... Que fais-je là-dessus ? Trois choses, dans l'ordre d'exécution :
- La déclaration de la variable toto.
- L'allocation de la mémoire pour cette variable
- L'initialisation de l'objet.
Plus haut je vous ai dit qu'on pouvait envoyer des messages à des méthodes, déjà on a définit des méthodes dans ce but, ce sont les méthodes dont la déclaration commence par un "
Alors vous voyez c'est assez simple. Pour l'instant je ne vous ai montré que des paramètres écrit "à la volée", c'est-à-dire écrite directement là où elle est demandée. Mais lorsqu'il s'agit de mettre en paramètre des objets quelconques déjà définit depuis longtemps, et bien il suffit de remplacer le "
Voilà, j'espère que ce concept, relativement simple, et bien compris. Maintenant, nous pouvons attaquer la définition de l'implémentation de nos méthodes !
L'@implementation d'une classe :

Cliquez sur le fichier "Personnel.m", ce fichier est déjà plus simple ! Voici ce que vous devriez avoir :
Alors vous revoyez notre petite directive "
Là, on initialise notre variable à 0 parce qu'aucun numéro n'a encore été attribué . Et ici, cette variable ne dépendra d'aucun objet, par contre, elle pourra être manipulée par n'importe qui... Enfin, on n'est pas censés savoir qu'elle existe :P.
Bon maintenant que ce problème de variable de classe est réglé et qui, de toutes façons, n'est pas un vrai problème ! On va pouvoir s'attaquer à la définition de l'implémentation des méthodes. Alors c'est un peu comme en C, l'implémentation d'une méthode a la même gueule que sa déclaration, à part qu'on remplace le point-virgule ";" de la deuxième par des accolades "{ }" dans la première entre lesquelles vous écrirez votre implémentation.
Déjà, vous vous en doutez j'espère, les définitions des méthodes vont se trouver entre les balises "
Les Méthodes Simples :
Sur les 10 méthodes que j'ai défini, 5 d'entre elles sont d'une simplicité déconcertante, elles renvoient seulement la valeur d'un attribut, on va commencer par elles parce qu'elles ne sont pas très très compliquées. Je ne vous donne pas les définitions dans l'ordre mais il vaut mieux qu'elles le soient pour vous reperer plus facilement, même un classement par méthodes de classe/méthodes d'instance et ensuite par ordre alphabétique, ou alors par nombre de paramètre, enfin trouvez le meilleur classement, celui qui vous fera le moins chercher vos méthodes. Commençons donc par 4 de ces 5 fameuses méthodes :
Bon, pas de grande difficulté, comme en C, nos méthodes retourne quelque chose, il se trouve, comme par hasard , que le type retourné est écrit dans le nom de la méthode
, et il se trouve que pour retourner quelque chose on met le mot clé "
On va s'occuper de la 5ème méthode qui ne fait que retourner une valeur, notre fameuse méthode "string", voici comment je l'ai implémentée :
Cette méthode est intéressante car on y voit déjà qu'on peut retourner directement la valeur donnée par le message, sans la stocker nul part. Ensuite on remarque un truc que je trouve assez amusant. Pour ceux qui connaissent bien le C, et notamment la fonction "printf();" qui permet d'afficher un message sur une console (comme le terminal), vous pouvez reconnaître quelques trucs dans cette fonction. Si je veux transformer cette méthode en printf, on aura à peu près ça :
"
Vous remarquez que le fonctionnement est identique, en fait la chaîne qui commence par un "
Pour le "%@", c'est un peu spécial, il doit être remplacé par un objet Objective-C, en fait pour que cela fonctionne, il faut qu'une certaine méthode soit implémentée dans la classe de l'objet. Alors vous avez le choix. Soit vous implémentez la méthode "descriptionWithLocal:", et là votre chaîne changera selon la langue spécifiée, soit vous implémentez la méthode "description", qui sera récupérée par "%@" si il ne trouve pas de "descriptionWithLocal:" dans la spécification de l'objet. Donc cette méthode retourne, comme son nom l'indique, une description sous forme de chaîne de caractères de votre classe, c'est exactement ce que l'on veut. Ainsi au lieu d'appeler chaque méthode pour récupérer les valeurs des attributs puis les affichés, il suffit de spécifier une NSString qui sera renvoyé puis affichée telle que vous l'avez souhaité !
Vous pouvez aussi voir à la fin l'utilisation de l'opérateur ternaire "
Au final, la méthode de classe créera cette NSString et notre méthode la renverra à quelqu'un qui voudra peut-être l'afficher ou bien se torcher avec au choix !
Les Méthodes Plus Complexes :
Maintenant, on va s'attaquer aux méthodes un peu plus complexes par ordre de difficulté, bon de toutes façons ce sera vite vu, d'abord la mathode qui permet de modifier le numéro de téléphone, suivit de la méthode d'initialisation, suivit des deux méthodes de création (allocation/initialisation) puis enfin la méthode de désallocation.
Je vous rappelle notre petite méthode de modification de donnée :
Alors le but de cette fonction est de modifier ou d'attribuer un numéro de téléphone, puisqu'il est possible de créer un Personnel sans numéro de téléphone. Voici son implémentation :
Ici nous utilisons une méthode de classe pour allouer la chaîne de caractères. Nous réutiliserons cette méthode pour l'initialisation de nos chaînes. L'avantage avec les NSString c'est qu'il n'est pas nécessaire de vider l'emplacement mémoire pour ensuite réallouer la mémoire ce qui permet d'éviter la gestion de leur mémoire... Gestion très emmerdante dans beaucoup d'autres cas... Donc une simple réallocation (si le téléphone était déjà inscrit) suffit dans notre cas. En revanche, la réallocation est nécessaire car comme je vous l'ai dit plus haut cette étape est nécessaire puisqu'une NSString n'est pas modifiable contrairement aux String du Java et du C++, pour avoir l'équivalent de ces chaîne modifiable en Objective-C, on utilise la classe héritant de NSString qui est NSMutableString, avec cette classe vous pouvez faire les modifications que vous voulez sans avoir besoin de supprimer quoique ce soit. Si dans ce cas on n'utilise pas ce système c'est que le numéro de téléphone n'est pas fait pour changer toutes les dix minutes.
Nous allons passer aux 3 méthodes d'initialisation / création de notre classe. Et nous allons les utiliser en cascade, c'est-à-dire qu'elles vont s'appeler les unes les autres. Déjà implémentons notre initialisation :
Alors cette petite méthode est très importante, non seulement parce qu'elle permet d'initialiser nos objets correctement, mais surtout parce qu'ils 'agit en l'occurrence de l'initialiseur désigné. Mais qu'est-ce que c'est ? Il s'agit en fait de la méthode d'initialisaiton que les autres méthodes devront absolument appelé, et dont à cet effet, elle doit donc prendre le plus de paramètres, initialisant des attributs, possibles en l'occurrence notre méthode initialise les deux seuls attributs que l'on veut initialiser donc ça marche.
Donc, quand on lit cette implémentation on tombe sur quelque chose de surprenant dès le "if", cette instructions contenant 2 mots clés et une méthode :
Déjà "
Parlons de ces instructions, pour la première on utilise notre pseudo-variable de classe, on fait de la préincrémentation, c'est-à-dire que le "
On va maintenant passer en revu nos deux méthodes de classe permettant l'allocation et l'initialisation de nos objets ! Alors, comme je l'ai dit plus haut, chaque classe ne doit avoir qu'une seule méthode désignée, c'est-à-dire qu'une seule méthode qui appelle l'initialiseur de la classe supérieur, et les autres méthodes d'initialisation doivent appeler cet initialiseur désigné, et c'est ce que nous allons faire ! Mais il faut toujours faire l'allocation, sinon notre méthode ne sert à rien ! Donc voici l'implémentation des deux méthodes :
Déjà vous voyez que les méthodes et les messages sont sur plusieurs lignes, en fait chaque argument est sur une ligne, ça permet d'être plus clair car lorsque vos méthodes commencent à avoir 3, 4, 5 paramètres (on va en voir) vous allez avoir mal à la tête, l'avantage est que Xcode aligne vos méthodes automatiquement sur les "
Alors pour ceux qui ont un peu suivit, vous remarquerez sans doute quelque chose de surprenant... Le fait que j'utilise "self" comme receveur d'une méthode de classe, et bien ce n'est pas grave puisque de toutes façon une classe est aussi un objet classe :P et puis de toutes façons on n'a pas le choix ! Donc, on alloue de la RAM à "self" et on l'initialise avec notre petite méthode définie plus haut ! Et ensuite on retourne l'objet bien initialisé. Tout simplement, et notre autre méthode n'a plus rien à faire qu'à utiliser l'autre méthode d'allocation... En lui envoyant l'argument "nil" qui est géré dans la méthode d'initialisation. J'espère qu'il n'y a pas de problème ! Parce que c'est pas vraiment compliqué.
Voilà, on peut attaquer la dernière partie de ce tutoriel, concernant une méthode très importante ! La méthode "dealloc", cette méthode, vous ne l'invoquerez JAMAIS dans vos programmes, le seul endroit où vous allez invoquer cette méthode est dans la déclaration de votre propre dealloc ! Enfin, je vais vous expliquer tout de suite, mais voici la syntaxe :
Alors, de la même manière qu'on a invoqué la méthode "init" de "super" au début de notre initialiseur, nous invoquons la méthode "dealloc" de "super" à la fin de notre méthode "dealloc", et oui, tout doit finir comme cela a commencé ! C'est d'ailleurs pour ça que l'on trouve les deux messages précédents. La méthode "release" et celle que vous invoquerez lorsque vous aurez besoin de supprimer un objet. En effet, "dealloc" sera appelée par cette méthode "release", en fait, elle ne sera appelé par "release" que lorsque toute les références à votre objet seront supprimées pas avant. Car un même objet peut être référencé à plusieurs endroits selon les besoins. Vous savez qu'on a alloué 2 NSString dans notre initialisation, il n'est pas nécessaire de leur envoyé le message "release", elles sont évacuées automatiquement donc vous n'avez pas à vous en soucier, en revanche les autres types d'objets auront besoin d'être relâché avant que votre classe ne soit désallouée. Et donc pour seule instruction de notre méthode, on appelle la méthode de désallocation de la classe "super" pour que l'objet meurt dans de bonnes conditions sans occuper la mémoire pour rien.
Enfin, voilà, nous avons défini une classe, nous avons écrit son fichier d'en-tête, avec la déclaration des méthodes et la déclaration de ses attributs. Nous avons écrit son fichier source, avec les définitions de toutes les méthodes de classe et d'instance. Nous avons donc définit tous les éléments nécessaires au bon fonctionnement d'une classe de base. Alors le tutoriel d'Objective-C ne fait que commencer. La programmation orientée-objet est un domaine assez vaste, et Mac OS X étant encore ce domaine.
Donc voilà ce qui conclut le premier épisode sur la programmation orientée-objet en Objective-C. Étant donné mes activités estudiantines je ne peux vous garantir la parution de l'épisode suivant, mais je vais faire tout mon possible pour vous le fournir rapidement.
Comme d'habitude si vous avez des questions, des suggestions, des commentaires, vous connaissez les divers chemins .
Psycho
PS : Ce site a un contenu très riche ! Si vous avez besoin de plus d'informations, de plus d'aide vous avez notamment :
- Mon Adresse E-mail
- Le Forum de LogicielMac
- Voire même la section Développement & Bêta du forum
Alors si vous avez un problèmes, des questions, des suggestions n'hésitez pas à venir ! N'hésitez pas non plus à venir pour nous exposer vos expériences en programmation ! En clair visitez notre forum ! ;)
@Leonie Plus d'un an et demi pour répondre, je pense que tu auras trouvé (et pas abandonné, j'espère !). Enfin, pour ceux qui liraient ce tuto à partir d'auj. : Xcode se trouve sur le DVD de Mac OS X fourni avec l'ordi (ou acheté en version boîte). Il faut installer les outils développeur. Dasn Optional Installs>Xcode Tools>Xcodetools.mpkg :)