LogicielMac.com
  • twitter
  • facebook
  • Accueil
  • Forum
  • Logiciels
    • Internet
    • Pratique
    • Utilitaire
    • Multimédia
    • Sécurité
    • Jeux
  • Rubriques
    • Actualités
    • Screencast
    • Articles
  • Espace développeurs
  • Boutique
LogicielMac.com
  • Accueil
  • Forum
  • Logiciels
    • Internet
    • Pratique
    • Utilitaire
    • Multimédia
    • Sécurité
    • Jeux
  • Rubriques
    • Actualités
    • Screencast
    • Articles
  • Espace développeurs
LogicielMac.com
  • Accueil
  • Forum
  • Logiciels
    • Internet
    • Pratique
    • Utilitaire
    • Multimédia
    • Sécurité
    • Jeux
  • Rubriques
    • Actualités
    • Screencast
    • Articles
  • Espace développeurs
  • Boutique
  • Accueil
  • News
  • Actualités
  • La Programmation : Le Langage Objective-C (1)
Actualités
Tweeter
La Programmation : Le Langage Objective-C (1)

La Programmation : Le Langage Objective-C (1)

Actualité rédigée par le 02/12/2006 à 23:02

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 :
      1. Baghera, mâle, noir...
      2. Ashoka, femelle, gris
      3. Boulawane, mâle, noir et blanc
      4. 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.

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

// // Personnel.h // Tutoriel_CLU // // Created by __MyName__ on 30/11/2006. // Copyright 2006 __MyCompanyName__. All rights reserved. // #import @interface Personnel : NSObject { } @end

Si vous êtes habitués au C, une première chose ne devrait pas vous échapper, c'est la directive de préprocesseur "#import ". Cette directive est l'équivalent de "#include ", mais elle a l'avantage de gérer le problème des inclusions multiples. En effet, en C, lorsque vous définissez un fichier d'en-tête, vous devez faire attention, dans votre code, de bien spécifier ceci :

#ifndef MACLASSE_H_ #define MACLASSE_H_ //Vos déclarations #endif

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 "@interface" et "@end ". Alors entre le mot clé "@interface " et les deux nous pouvons voir le nom de la classe, après se situe le nom de la classe dont hérite notre classe (Nous verrons la notion d'héritage plus tard), en Objective-C, (contrairement au C++), toutes les classes héritent obligatoirement de la classe NSObject directement ou indirectement (c'est-à-dire qu'elles peuvent hériter d'une classe qui elle-même hérite de NSObject).

 

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 : type nom_variable;.
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 : int, float, double, void, etc. + type générique de l'Objective-C : BOOL, SEL, id) la déclaration peut se faire sous forme de variable statique ou de pointeurs, la déclaration des attributs d'une certaine classe se fait uniquement par pointeur. Si vous voulez vous faire incendier par le compilateur donnez-lui un objet défini statiquement. En effet, Objective-C est un langage entièrement dynamique, c'est-à-dire que les objets sont créés et supprimés de la mémoire à l'exécution du programme lorsqu'ils sont appelés... Pas au démarrage du programme comme dans le cas des variables statiques 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 :
#import @interface Personnel : NSObject { int numPers; NSString * nomPers; NSString * numTel; } @end

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é "@end ". Et c'est à parti de là qu'on pourra commencer à entrevoir le côté pratique de ce langage.

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 ou NO 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 : "maMethodePrendUneChaine:etUnEntier:", vous pouvez voir que les types ne sont pas pris en compte dans la définition. C'est à la fois un avantage et un problème : si vous avez à redéfinir les types pris par une méthode le compilateur ne s'en offusquera pas. Par contre, ça le gènera si vous donnez à la fonction un paramètres de type différent... Surtout au niveau de l'exécution ! Sauf si il s'agit d'un type générique, là il y a moins de problème. Mais soyez tout de même vigilants !

 

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 :
+ (id) personnelWithNom: (NSString*) unNom; // Allocation + Initialisation avec le nom du personnel + (id) personnelWithNom: (NSString*) unNom andNumTel: (NSString*) unNumTel; // Même chose avec en plus le numTel + (int) dernierNumPers; // Retourne le dernier numéro attribué qui sera une variable globale, // nous en verrons plus tard - (id) initWithNom: (NSString*) unNom andNumTel: (NSString*) unNumTel; // Initialisation sans allocation - (int) numPers; // Retourne le numéro du Personnel - (NSString*) nomPers; // Retourne son nom - (NSString*) numTel; // Retourne son numéro de tel - (void) setNumTel: (NSString*) unNumTel; // Au cas où il faille attribuer le numéro de tel voire le changer - (NSString*) description; // Nous sommes en mode commande, cette méthode permettra l'affichage dans ce mode. - (void) dealloc; // Permet la désallocation.

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 "string" a été remplacée par la méthode "description", les explications sont dans l'implémentation de cette 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 : [receveur message]

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 :
int numero = [toto numPers];

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" :
[toto setNumTel:@"00 34 5 00 00 00 01"];

Alors, on voit déjà deux trucs, cette méthode ne renvoie rien ( void ), donc pas besoin de récupération de valeurs. Ensuite on voit ce : "@"..."", ça c'est une chaîne de caractères style d'Objective-C, cela représente une chaîne NSString tout simplement. Si vous ne mettez pas le "@" ce sera une chaîne typiquement C.

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 :
Personnel *toto = [[Personnel alloc] initWithNom:@"toto" andNumTel:@"00 34 5 00 00 00 01"];

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 "+". Mais là, j'envoie à la classe Personnel, le message "alloc", on n'a pourtant rien définit de tel ! En fait, vous entrevoyez la notion d'héritage, cette méthode n'est pas définie dans Personnel, mais dans NSObject, classe contenant beaucoup de méthode très utile, cette méthode renvoie un pointeur sur un Personnel complètement anarchique, si vous faites des actions là-dessus ça va vous faire mal à la gueule, d'où l'intérêt de ne faire qu'une instruction. L'initialisation se fait juste après sur ce pointeur et renvoie à nouveau le pointeur sur l'objet, notre petite variable toto récupère tout simplement cette adresse et devient en quelque sorte cet objet. Et c'est à partir de cette simple ligne que l'on peut exécuter les deux précédents messages.

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 "@""" par le nom de la variable.

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 :
// // Personnel.m // Tutoriel_CLU // // Created by __MyName__ on 30/11/2006. // Copyright 2006 __MyCompanyName__. All rights reserved. // #import "Personnel.h" @implementation Personnel @end

Alors vous revoyez notre petite directive "#import ", c'est généralement la seule qu'on voit dans ce fichier-là, on laisse les autres au fichier d'en-tête. Par contre, c'est dans ce fichier qu'on va définir la variable de classe dont je vous ai parlé plus haut. Dans Objective-C, les variables de classes n'existent pas en tant que telles, c'est-à-dire qu'aucune variable définit dans la classe n'est identique dans toutes ses instances. Ça peut nous emmerder ! Alors on peut contourner ce problème en déclarant cette variable entre la diréctive d'importation et l'implémentation de la classe. Comme celà :
#import "Personnel.h" int dernierNumPers = 0; @implementation Personnel

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 " @implementation" et "@end " et en plus, la balise "@implementation " rappelle le nom de la classe implémentée. Après il s'agit d'une simple méthode comme une autre.

 

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 :
+ ( int ) dernierNumPersAttribue { return dernierNumPers; } - ( int ) numPers { return numPers; } - (NSString*) nomPers { return nomPers; } - (NSString*) numTel { return numTel; }

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é " return " suivi de la variable retournée.

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 :
- (NSString*) description { return [NSString stringWithFormat:@"Membre du personnel \nNuméro : %d\n Nom :%@\nTéléphone :%@\n",numPers,nomPers,numTel]; }

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 :
printf("Membre du personnel :\nNuméro : %d\n Nom :%s\nTéléphone :%s\n" , numPers,nomPers,(numTel ? numTel : "" ));
"nomPers" et "numTel" doivent être du type "char *"

Vous remarquez que le fonctionnement est identique, en fait la chaîne qui commence par un "@"" " s'appelle un format, car elle peut comporter des caractère commençant par "\" et "%" et qui définissent la forme sous laquelle apparaîtra la chaîne au final. Par exemple "\n" permet un retour à la ligne, et "%d" sera remplacé par un entier, ces "%" sont les mêmes qu'en C, plus le "%@ " et ensuite pour définir les variables qui remplaceront ces caractères spéciaux, c'est comme en C, il suffit de mettre à la suite du format, chacune des variables séparées par des virgules et ça c'est possible à chaque fois qu'on demande un format. Le côté pratique de ce système est de permettre la conversion, qui n'est pas évidente, d'un entier ou d'un réel, par exemple, en une chaîne de caractères.

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 "? :", en effet quand un objet est correctement initialisé, ça valeur peut-être "nil", qui est l'équivalent du "NULL" dans le langage C mais pour les objets, il existe aussi "Nil" qui est lui l'équivalent pour les classes. Et ces 3 mots clés, bien qu'ayant des fonctions différentes sont tous égaux à 0, et donc au booléen "NO", ainsi, si notre employé n'a pas de numéro de téléphone (numTel = nil), et bien la chaîne qui sera affichée sera la chaîne "@"""

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 :
- (void) setNumTel: (NSString*) unNumTel;

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 :
- (void) setNumTel: (NSString*) unNumTel { // Partie Modifiée numTel = [NSString stringWithString:unNumTel]; }

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 :
- (id) initWithNom: (NSString*) unNom andNumTel: (NSString*) unNumTel { if(self = [super init]) { numPers = ++dernierNumPers; nomPers = [NSString stringWithString:unNom]; numTel = (unNumTel ? [NSString stringWithString:unNumTel] : nil); return self; } return nil; }

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 :

self = [super init]

Déjà "self " (soi), désigne un pointeur sur l'objet en cours, et "super " désigne la classe supérieur, dans la hiérarchie des héritages, en l'occurrence il s'agit de NSObject. De cette classe, on invoque la méthode "init" qui permet d'initialiser l'objet en mémoire correctement. Un initialiseur désigné doit toujours invoquer cette méthode, sous peine d'avoir un objet complètement branquignole et inutilisable à l'arrivée. Si cette méthode est utile c'est qu'il faut pouvoir initialisé tous les attributs (nombreux) de la classe NSObject qui sont, grâce à la notion d'héritage, aussi ceux de notre classe. Donc la méthode retournera, ou non, un objet bien formé et l'affectera à notre objet courant "self", si jamais cette initialisation se passait mal et que l'objet n'aurait pu l'être correctement. La méthode "init" retournerait "nil", "self" aurait alors aussi la valeurs "nil" et le "if" ne serait pas exécuté (je rappelle que "nil" = 0 = "NO" donc le "if" ne s'exécute pas), notre méthode retournerait alors "nil" et donc nous n'aurions aucune chance de manipuler des données erronées. Bon, dans la majorité des cas, l'initialisation se passe bien et les instructions contenues dans le "if" sont exécutées.

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 "++" se trouve avant la variable, on incrémente et ensuite on affecte cette variable au numéro de compte. Pour la deuxième, il s'agit de l'affectation du nom, alors ici on doit allouer la mémoire puis initialiser notre vaiable à la valeur donnée. Rien de bien difficile. Pour la troisième, vous voyez à nouveau notre opérateur ternaire. Il est nécessaire car nous avons un initialiseur qui ne prend pas le numéro de téléphone en paramètre et qui l'initialisera à "nil", le système n'appréciera pas que vous initialisez une chaîne à l'aide de la méthode "stringWithString:" si son argument est "nil". Lorsqu'on a finit toutes nos initialisations, on renvoie notre objet terminé et bien initialisé, bon si le "if" ne s'est pas exécuté on renvoie "nil".

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 :
+ (id) personnelWithNom: (NSString*) unNom { return [self personnelWithNom:unNom andNumTel:nil]; } + (id) personnelWithNom: (NSString*) unNom andNumTel: (NSString*) unNumTel { return [[self alloc] initWithNom:unNom andNumTel:unNumTel]; }

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 ": ", pratique non??? :P Ensuite vous voyez que dans la première méthode on appelle la deuxième... bah oui quel intérêt de faire deux fois la même choses dans deux méthodes différentes alors qu'il y a une méthode qui fait ça très bien ! Mais vous allez me dire : "Ah mais ça pompe la mémoire en appel, on passe par plusieurs méthode pour pas faire grand chose de plus, et finalement on pourrait laisser l'utilisateur faire le choix de sa méthode !" Oui ! Mais, déjà ce n'est pas un enchaînement de 4 méthodes qui fera surchauffer votre processeur ! Ensuite, ici ça n'a peut-être aucun intérêt, mais ça vous permet de voir ce qu'il est possible de faire et surtout de montrer qu'on peut et qu'il faut pouvoir donner plusieurs solutions à l'utilisateurs pour éviter qu'ils fassent des conneries irréparables.

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 :
- (void) dealloc { // Partie Modifiée [super dealloc]; }

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 ! ;)

Lire une autre news :
Actualités
Tweeter

La Programmation : Le Langage Objective-C (1)

Actualité rédigée par le 02/12/2006 à 23:02
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 :
      1. Baghera, mâle, noir...
      2. Ashoka, femelle, gris
      3. Boulawane, mâle, noir et blanc
      4. 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.

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

// // Personnel.h // Tutoriel_CLU // // Created by __MyName__ on 30/11/2006. // Copyright 2006 __MyCompanyName__. All rights reserved. // #import @interface Personnel : NSObject { } @end

Si vous êtes habitués au C, une première chose ne devrait pas vous échapper, c'est la directive de préprocesseur "#import ". Cette directive est l'équivalent de "#include ", mais elle a l'avantage de gérer le problème des inclusions multiples. En effet, en C, lorsque vous définissez un fichier d'en-tête, vous devez faire attention, dans votre code, de bien spécifier ceci :

#ifndef MACLASSE_H_ #define MACLASSE_H_ //Vos déclarations #endif

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 "@interface" et "@end ". Alors entre le mot clé "@interface " et les deux nous pouvons voir le nom de la classe, après se situe le nom de la classe dont hérite notre classe (Nous verrons la notion d'héritage plus tard), en Objective-C, (contrairement au C++), toutes les classes héritent obligatoirement de la classe NSObject directement ou indirectement (c'est-à-dire qu'elles peuvent hériter d'une classe qui elle-même hérite de NSObject).

 

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 : type nom_variable;.
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 : int, float, double, void, etc. + type générique de l'Objective-C : BOOL, SEL, id) la déclaration peut se faire sous forme de variable statique ou de pointeurs, la déclaration des attributs d'une certaine classe se fait uniquement par pointeur. Si vous voulez vous faire incendier par le compilateur donnez-lui un objet défini statiquement. En effet, Objective-C est un langage entièrement dynamique, c'est-à-dire que les objets sont créés et supprimés de la mémoire à l'exécution du programme lorsqu'ils sont appelés... Pas au démarrage du programme comme dans le cas des variables statiques 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 :
#import @interface Personnel : NSObject { int numPers; NSString * nomPers; NSString * numTel; } @end

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é "@end ". Et c'est à parti de là qu'on pourra commencer à entrevoir le côté pratique de ce langage.

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 ou NO 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 : "maMethodePrendUneChaine:etUnEntier:", vous pouvez voir que les types ne sont pas pris en compte dans la définition. C'est à la fois un avantage et un problème : si vous avez à redéfinir les types pris par une méthode le compilateur ne s'en offusquera pas. Par contre, ça le gènera si vous donnez à la fonction un paramètres de type différent... Surtout au niveau de l'exécution ! Sauf si il s'agit d'un type générique, là il y a moins de problème. Mais soyez tout de même vigilants !

 

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 :
+ (id) personnelWithNom: (NSString*) unNom; // Allocation + Initialisation avec le nom du personnel + (id) personnelWithNom: (NSString*) unNom andNumTel: (NSString*) unNumTel; // Même chose avec en plus le numTel + (int) dernierNumPers; // Retourne le dernier numéro attribué qui sera une variable globale, // nous en verrons plus tard - (id) initWithNom: (NSString*) unNom andNumTel: (NSString*) unNumTel; // Initialisation sans allocation - (int) numPers; // Retourne le numéro du Personnel - (NSString*) nomPers; // Retourne son nom - (NSString*) numTel; // Retourne son numéro de tel - (void) setNumTel: (NSString*) unNumTel; // Au cas où il faille attribuer le numéro de tel voire le changer - (NSString*) description; // Nous sommes en mode commande, cette méthode permettra l'affichage dans ce mode. - (void) dealloc; // Permet la désallocation.

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 "string" a été remplacée par la méthode "description", les explications sont dans l'implémentation de cette 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 : [receveur message]

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 :
int numero = [toto numPers];

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" :
[toto setNumTel:@"00 34 5 00 00 00 01"];

Alors, on voit déjà deux trucs, cette méthode ne renvoie rien ( void ), donc pas besoin de récupération de valeurs. Ensuite on voit ce : "@"..."", ça c'est une chaîne de caractères style d'Objective-C, cela représente une chaîne NSString tout simplement. Si vous ne mettez pas le "@" ce sera une chaîne typiquement C.

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 :
Personnel *toto = [[Personnel alloc] initWithNom:@"toto" andNumTel:@"00 34 5 00 00 00 01"];

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 "+". Mais là, j'envoie à la classe Personnel, le message "alloc", on n'a pourtant rien définit de tel ! En fait, vous entrevoyez la notion d'héritage, cette méthode n'est pas définie dans Personnel, mais dans NSObject, classe contenant beaucoup de méthode très utile, cette méthode renvoie un pointeur sur un Personnel complètement anarchique, si vous faites des actions là-dessus ça va vous faire mal à la gueule, d'où l'intérêt de ne faire qu'une instruction. L'initialisation se fait juste après sur ce pointeur et renvoie à nouveau le pointeur sur l'objet, notre petite variable toto récupère tout simplement cette adresse et devient en quelque sorte cet objet. Et c'est à partir de cette simple ligne que l'on peut exécuter les deux précédents messages.

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 "@""" par le nom de la variable.

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 :
// // Personnel.m // Tutoriel_CLU // // Created by __MyName__ on 30/11/2006. // Copyright 2006 __MyCompanyName__. All rights reserved. // #import "Personnel.h" @implementation Personnel @end

Alors vous revoyez notre petite directive "#import ", c'est généralement la seule qu'on voit dans ce fichier-là, on laisse les autres au fichier d'en-tête. Par contre, c'est dans ce fichier qu'on va définir la variable de classe dont je vous ai parlé plus haut. Dans Objective-C, les variables de classes n'existent pas en tant que telles, c'est-à-dire qu'aucune variable définit dans la classe n'est identique dans toutes ses instances. Ça peut nous emmerder ! Alors on peut contourner ce problème en déclarant cette variable entre la diréctive d'importation et l'implémentation de la classe. Comme celà :
#import "Personnel.h" int dernierNumPers = 0; @implementation Personnel

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 " @implementation" et "@end " et en plus, la balise "@implementation " rappelle le nom de la classe implémentée. Après il s'agit d'une simple méthode comme une autre.

 

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 :
+ ( int ) dernierNumPersAttribue { return dernierNumPers; } - ( int ) numPers { return numPers; } - (NSString*) nomPers { return nomPers; } - (NSString*) numTel { return numTel; }

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é " return " suivi de la variable retournée.

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 :
- (NSString*) description { return [NSString stringWithFormat:@"Membre du personnel \nNuméro : %d\n Nom :%@\nTéléphone :%@\n",numPers,nomPers,numTel]; }

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 :
printf("Membre du personnel :\nNuméro : %d\n Nom :%s\nTéléphone :%s\n" , numPers,nomPers,(numTel ? numTel : "" ));
"nomPers" et "numTel" doivent être du type "char *"

Vous remarquez que le fonctionnement est identique, en fait la chaîne qui commence par un "@"" " s'appelle un format, car elle peut comporter des caractère commençant par "\" et "%" et qui définissent la forme sous laquelle apparaîtra la chaîne au final. Par exemple "\n" permet un retour à la ligne, et "%d" sera remplacé par un entier, ces "%" sont les mêmes qu'en C, plus le "%@ " et ensuite pour définir les variables qui remplaceront ces caractères spéciaux, c'est comme en C, il suffit de mettre à la suite du format, chacune des variables séparées par des virgules et ça c'est possible à chaque fois qu'on demande un format. Le côté pratique de ce système est de permettre la conversion, qui n'est pas évidente, d'un entier ou d'un réel, par exemple, en une chaîne de caractères.

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 "? :", en effet quand un objet est correctement initialisé, ça valeur peut-être "nil", qui est l'équivalent du "NULL" dans le langage C mais pour les objets, il existe aussi "Nil" qui est lui l'équivalent pour les classes. Et ces 3 mots clés, bien qu'ayant des fonctions différentes sont tous égaux à 0, et donc au booléen "NO", ainsi, si notre employé n'a pas de numéro de téléphone (numTel = nil), et bien la chaîne qui sera affichée sera la chaîne "@"""

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 :
- (void) setNumTel: (NSString*) unNumTel;

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 :
- (void) setNumTel: (NSString*) unNumTel { // Partie Modifiée numTel = [NSString stringWithString:unNumTel]; }

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 :
- (id) initWithNom: (NSString*) unNom andNumTel: (NSString*) unNumTel { if(self = [super init]) { numPers = ++dernierNumPers; nomPers = [NSString stringWithString:unNom]; numTel = (unNumTel ? [NSString stringWithString:unNumTel] : nil); return self; } return nil; }

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 :

self = [super init]

Déjà "self " (soi), désigne un pointeur sur l'objet en cours, et "super " désigne la classe supérieur, dans la hiérarchie des héritages, en l'occurrence il s'agit de NSObject. De cette classe, on invoque la méthode "init" qui permet d'initialiser l'objet en mémoire correctement. Un initialiseur désigné doit toujours invoquer cette méthode, sous peine d'avoir un objet complètement branquignole et inutilisable à l'arrivée. Si cette méthode est utile c'est qu'il faut pouvoir initialisé tous les attributs (nombreux) de la classe NSObject qui sont, grâce à la notion d'héritage, aussi ceux de notre classe. Donc la méthode retournera, ou non, un objet bien formé et l'affectera à notre objet courant "self", si jamais cette initialisation se passait mal et que l'objet n'aurait pu l'être correctement. La méthode "init" retournerait "nil", "self" aurait alors aussi la valeurs "nil" et le "if" ne serait pas exécuté (je rappelle que "nil" = 0 = "NO" donc le "if" ne s'exécute pas), notre méthode retournerait alors "nil" et donc nous n'aurions aucune chance de manipuler des données erronées. Bon, dans la majorité des cas, l'initialisation se passe bien et les instructions contenues dans le "if" sont exécutées.

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 "++" se trouve avant la variable, on incrémente et ensuite on affecte cette variable au numéro de compte. Pour la deuxième, il s'agit de l'affectation du nom, alors ici on doit allouer la mémoire puis initialiser notre vaiable à la valeur donnée. Rien de bien difficile. Pour la troisième, vous voyez à nouveau notre opérateur ternaire. Il est nécessaire car nous avons un initialiseur qui ne prend pas le numéro de téléphone en paramètre et qui l'initialisera à "nil", le système n'appréciera pas que vous initialisez une chaîne à l'aide de la méthode "stringWithString:" si son argument est "nil". Lorsqu'on a finit toutes nos initialisations, on renvoie notre objet terminé et bien initialisé, bon si le "if" ne s'est pas exécuté on renvoie "nil".

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 :
+ (id) personnelWithNom: (NSString*) unNom { return [self personnelWithNom:unNom andNumTel:nil]; } + (id) personnelWithNom: (NSString*) unNom andNumTel: (NSString*) unNumTel { return [[self alloc] initWithNom:unNom andNumTel:unNumTel]; }

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 ": ", pratique non??? :P Ensuite vous voyez que dans la première méthode on appelle la deuxième... bah oui quel intérêt de faire deux fois la même choses dans deux méthodes différentes alors qu'il y a une méthode qui fait ça très bien ! Mais vous allez me dire : "Ah mais ça pompe la mémoire en appel, on passe par plusieurs méthode pour pas faire grand chose de plus, et finalement on pourrait laisser l'utilisateur faire le choix de sa méthode !" Oui ! Mais, déjà ce n'est pas un enchaînement de 4 méthodes qui fera surchauffer votre processeur ! Ensuite, ici ça n'a peut-être aucun intérêt, mais ça vous permet de voir ce qu'il est possible de faire et surtout de montrer qu'on peut et qu'il faut pouvoir donner plusieurs solutions à l'utilisateurs pour éviter qu'ils fassent des conneries irréparables.

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 :
- (void) dealloc { // Partie Modifiée [super dealloc]; }

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 ! ;)

Lire une autre news :

Les commentaires sur Logiciel Mac

Commentaires Articles

Arcank le 20/03/2009 04:37

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

Anonyme le 21/09/2007 08:57

moi j'ai un probleme je trouve pas xcode sous mon mac est-ce que quelqun sait si on peut le telecharger queque part parcque j'aimerai bin rogramer en c ... si vous savez ou je pourai en trouver hésitez pas a me le faire savoir merci

Anonyme le 03/02/2007 01:45

Question/Suggestion: la definition de dernierNumPersAttribue devrait plutot etre dernierNumPers tout court, non? En tout cas cela fait disparaitre 2 warnings et cela continue a fonctionner.

Anonyme le 03/02/2007 01:26

Excellent tuto! Merci beaucoup PsychoH13. Bel effort. B)

PsychoH13 le 07/12/2006 12:59

Bah par exemple, en Java, le procédural n'existe pas, en java tu ne peux pas faire de nouvelle classe racine (ce qui est proprement inutile), en objective-C tu n'as pas de variable globale, en Java tu ne peux pas étendre une classe sans recompiler le code, en Objective-C c'est possible, en Java tu n'as pas de structure, que des classes, en Objective C tu as des structures telles qu'enum, struct, union, le java est un langage interprété et l'objective-C est compilé, en objective-C tu n'as qu'un seul type d'exception alors qu'en java tu as une nouvelle classe pour un nouveau type d'exception... etc. Enfin je peux pas répertorier toutes les différences, je vais essayer d'en fair eune meilleure liste un jour ou l'autre.

Anonyme le 07/12/2006 04:34

Question bête : qu?est-ce qu?on ne peut pas faire en Java mais que Objective-C autorise ? À l?inverse, y a-t-il des choses qu?on peut faire en Java et aps en Objective-C ? Oui, c?est assez bête comme question :roll:

PsychoH13 le 06/12/2006 02:24

Ekami... je vois pas pourquoi Apple ou Microsoft permettrait une compilation pour l'autre système... C'est d'ailleurs pas fait pour ça du tout !!! Et ça fait longtemps qu'Apple propose de porté les applications Windows sur Mac OS X, ils ont publié des guides à cet effet ! Et Apple ne va pas porter les APIs Windaube sur Mac OS X !!! C'est un coup à récupérer les bugs et les failles de leur système. Les API de Mac OS X sont bien plus puissants que ceux de WIndows alors pourquoi rétrograder ?

Anonyme le 06/12/2006 01:22

C'est à Apple de le faire pour la simple et unique raison que jamais Microsoft ne le fera car : - Monopole oblige ils ne vont pas se tirer une balle dans le pied en incluant la compilation pour OSX dans leurs outils de dév au risque de voir des utilisateurs préférer OSX à Windows. - C'est à Apple et elle seule d'attirer les développeurs windows et de permettre à de nouveaux logiciels d'être portés sous OSX. Car chaque fois qu'un logiciel sort en version OSX et Windows, c'est la plateforme Mac qui grandit un peu plus. - C'est sur que je vois mal M$ collaborer avec Apple pour faciliter l'intégration de leurs frameworks et API dans XCode, mais c'est pourtant ce qu'il faudrait faire. Faisons confiance à MS pour trainer les pieds autant que possible pour empêcher cela. - Il reste bien sur que tester chaque correction de code dans les deux environnements augmente bcp le temps de dév, mais avec Parrellels et consorts ça doit être jouable. Mais bon, là ça dépasse de bcp mes connaissance de modeste codeur Transcript ( le langage de Runtime Revolution)

PsychoH13 le 06/12/2006 08:10

Windev ne compile pas pour windaube alors pourquoi, Xcode compilerait pour windows ;) Et puis sur Windows tu n'as pa sl'API Cocoa qu'on utilise sur Mac OS X :P

Anonyme le 06/12/2006 01:26

Mille mercis pour ce bon tuto. Je ne connais rien au C mais depuis plus de 10 ans que je ponds du Code Hypertalk ( on ne rigole pas au fond de la classe ;) ), j'ai fait de la POO comme M. Jourdain. C'est le concept de classe que je trouvais obscur, car les "classes" existantes dans HyperCard étaient plus que minimalistes : boutons et champs de texte (plus quelques classes annexes (fonds et cartes) et une "super-classe" (la pile elle même)). Quand je vois ce que j'ai réussi à faire avec seulement 5 classes, je n'ose imaginer l'immensité des possibilités offertes par XCode, ça fait vraiment rêver une telle puissance :D . Ce tuto me donne envie d'apprendre le C et de m'initier à XCode, juste à titre perso. Mais apparemment XCode ne compile pas pour Windows, et ça c'est sûrement très dommage. Mais bon, je n'en suis pas là... Alors, je me contenterais de la suite du tuto quand il sera dispo :p

Anonyme le 05/12/2006 04:32

Vraiment très bien ce tuto. J?attends avec impatience la suite. Après, j?envoie un CV à Apple et je bosse sur Mac OS X :p

Alésio le 03/12/2006 10:56

Mais c'est moult bien... en plus ça fait de la très bonne pub pour ce site puisqu'il est présenté en première page du SITE DU ZERO (quand on sait combien de personnes passent dessus...)!!!! Bravo ;) B)

Anonyme le 03/12/2006 08:01

Pourquoi sans xCode ? Parce que ça pèse des tonnes sur mon pauvre disque dur :roll: Mais bon? pas le choix apparemment. Vraiment j?ai très très envie d?apprendre Objective-C.

PsychoH13 le 03/12/2006 07:07

Oui je sais que ce langage est utilisé autre part... Mais c'est vraiment épisodique,, on peut pas dire que ce soit un langage majeure, alors que sous Mac OS X c'est un langage majeur. Et ça doit représenter 95% de l'utilisation d'Objective-C. OUI OUI Apple a le monopole dans certains secteurs :D

Anonyme le 03/12/2006 06:43

Si je peux me faire mettre, une petite erreur s'est glissée dans le début (la suite je pourrai pas vous dire, je l'ai pas lue) "Ce que je trouve dommage c'est que ce langage ne soit utilisé que sous Mac, et particulièrement avec l'API Cocoa." D'autres environnements supportent ObjC, comme GNUstep (vous reconnaissez le "-step" ? C'est un autre descendant de NeXT ;)), ou (mais j'ai pas testé) GTK, avec les bons ponts pour assurer le fonctionnement.

PsychoH13 le 03/12/2006 02:48

Bah il existe GCC mais c'est beaucoup moins pratique, pour le C c'est plutôt simple à utiliser mais dès qu''il s'agit de l'objective-C ça devient beaucoup plus galère... Et pourquoi veux-tu te passer de Xcode??? :D<br /> Et puis, pour avoir GCC tu dois l'installer avec Xcode. :D

Anonyme le 03/12/2006 02:30

Au fait, peut-on apprendre Objective-C sans se servir de xCode ? Existe-t-il une alternative ?<br> Encore merci B)

PsychoH13 le 03/12/2006 01:30

Le tutoriel a un peu été modifié

Anonyme le 03/12/2006 12:42

Alors ça c?est marrant je pensais à ça (un tuto Objective-C sur ce site) hier. C?est vrai en plus 8) Merci 1 000 fois, super boulot !!!!

CrazyJo le 03/12/2006 11:06

Génial !!! Bravo! :)

Anonyme le 03/12/2006 08:51

Merci beacoup, car des tuto sur l'Obj-C il y en a pas des masses ;)

Titanium le 03/12/2006 03:58

Félicitations Psycho... Super tuto !! ;)

Anonyme le 03/12/2006 03:04

ca tombe bien je voulais me metre a la prog mais la j'ai dejas mal a la tete :p :p :p

Imat le 03/12/2006 01:53

pfiouuuu merci, je mets ça de coté même si j'ai aps encore le courage de tout lire, Quel Boulot en tout cas !!!

Blackfight le 02/12/2006 11:52

merciii vive l'OBJ C mais pour moment jme met au C :D

PsychoH13 le 02/12/2006 11:34

@Daniel : Télécharge ce logiciel gratuit en anglais pour compiler du Pascal : http://www.versiontracker.com/dyn/moreinfo/macosx/28628

Anonyme le 02/12/2006 11:29

il y a pas de programation en pascal...Pascal, j'ai besoin de programer en pascal et ca n'existe pas sous mac :(

►► Voir plus de commentaires ◄◄
Laissez votre avis pour l'article La Programmation : Le Langage Objective-C (1) (Merci de rester correct et de respecter les différents intervenants.)
Veuillez entrer les caractères
de l’image ci-dessous :

Articles sur le même sujet

  • Les bons plans du mercredi
    Les bons plans du mercredi

    Little Snitch : arrêtez-vous sur cette promotion alléchante de Little Snitch, une application Mac développée...

    Lire la suite
  • Napoleon: Total War Gold Edition pour Mac annoncé au printemps
    Napoleon: Total War Gold Edition pour Mac annoncé au printemps

    Après le succès de Empire: Total War, Sega et Feral Interactive repartent en guerre avec le portage attendu du fameux...

    Lire la suite
  • Origin, une version Alpha arrive sur Mac
    Origin, une version Alpha arrive sur Mac

    Dans l’idée de convertir le plus grand nombre, les plateformes de téléchargement de jeux vidéo...

    Lire la suite
  • 10 nouveaux jeux Mac sur GOG
    10 nouveaux jeux Mac sur GOG

    Lancée en 2008 pour le plus grand bonheur des gamers nostalgiques, la plateforme éditée par CD Projekt et...

    Lire la suite
  • Apple : le titre dégringole malgré des chiffres record
    Apple : le titre dégringole malgré des chiffres record

    Apple vient de présenter les résultats financiers de son premier trimestre fiscal, qui s’étend de septembre...

    Lire la suite
  • Le Guide du Cloud est de retour
    Le Guide du Cloud est de retour

    Le guideducloud vient de subir un petit lifting : la nouvelle version de cet espace dédié à la suite Office en...

    Lire la suite
  • 10,000,000 enfin disponible pour Mac et PC sur Steam
    10,000,000 enfin disponible pour Mac et PC sur Steam

    Avec le succès grandissant des Puzzle-RPG sur iOS, l’éditeur de jeux EightyEight Games propose enfin sur Steam...

    Lire la suite

Les Apps les plus téléchargées

  • Télécharger AnyMP4 Audio Convertisseur pour Mac AnyMP4 Audio Convertisseur pour Mac -
  • Télécharger Apeaksoft Free Online Video Converter Apeaksoft Free Online Video Converter -
  • Télécharger OnyX OnyX - Optimisation
  • Télécharger VLC Media Player VLC Media Player - Lecteur Vidéo
  • Télécharger LiquidCD LiquidCD - Gravure
  • Télécharger Stuffit Expander Stuffit Expander - Compression
  • Télécharger Gimp Gimp - Imagerie

Suivez-nous

Suivez-nous Abonnez-vous
  • Contact
  • |
  • Annoncer sur LogicielMac.com
  • |
  • Mentions légales
  • |
  • CGU
  • |
  • Suivez-nous sur :
  • Twitter Twitter
  • Facebook Facebook
© 2025 Logiciel Mac
LogicielMac.com
  • Contact
  • Annoncer sur LogicielMac.com
  • Mentions légales
  • CGU
  • Suivez-nous sur :
  • Twitter Twitter
  • Facebook Facebook
LogicielMac.com
© 2025 Logiciel Mac