Débuter avec Objective-C

introduction

Les bases du C restant encore dans votre mémoire, il est temps de vous familiariser avec Objective-C. La principale différence avec C est qu'Objective-C est un langage de programmation orienté objet, tandis que C est un langage de programmation procédural. Cela signifie que nous devons d’abord comprendre les objets et leur relation avec les classes. Les autres concepts clés que nous allons explorer dans cet article sont la messagerie d'objet, l'encapsulation et l'héritage..


Les origines de Objective-C

Objective-C et Cocoa sont deux composants clés de la plate-forme iOS. Malgré le fait que la plate-forme iOS soit encore relativement jeune, Objective-C a été créé au début des années 1980 par Brad Cox et Tom Love chez StepStone. Le langage a été créé dans le but de combiner le langage de programmation C robuste et agile avec l’élégant langage Smalltalk. Objective-C est un sur-ensemble strict de C et, contrairement à C, il s’agit d’un langage de programmation de haut niveau. La principale différence entre C et Objective-C est que ce dernier est un langage de programmation orienté objet, alors que C est un langage de programmation procédural..

Comment iOS a-t-il fini par utiliser un langage développé dans les années 1980? Peu de temps après sa création par Steve Jobs, NeXT a octroyé une licence à Objective-C de StepStone. NeXT a créé NeXTSTEP, un kit d’interface utilisateur pour le système d’exploitation NeXT développé en Objective-C. Bien que NeXTSTEP fournisse un ensemble d'outils révolutionnaire, le système d'exploitation NeXT n'a que peu de succès sur le marché. En 1996, Apple a acquis NeXT et NeXTSTEP est devenu Cocoa. Ce dernier est devenu populaire avec l'introduction d'OS X en mars 2001 et plus tard avec la sortie de l'iPhone et du système d'exploitation iOS.


Programmation orientée objet

En programmation procédurale, un programme se compose de une série de procédures ou de routines qui sont exécutés pour atteindre un état particulier. En programmation orientée objet, cependant, une collection d'objets interagissent et travaillent ensemble pour terminer une tâche. Même si le résultat final peut être identique, la méthodologie et les paradigmes sous-jacents sont très différents. La modularité et la réutilisabilité du code sont deux des principaux avantages des langages de programmation orientés objet comme nous le verrons bientôt.


Objective-C, cacao et cacao tactile

Les nouveaux développeurs dans les écosystèmes iOS et OS X sont souvent déconcertés par la relation entre Objective-C, Cocoa (OS X) et Cocoa Touch (iOS). Qu'est-ce que Cocoa Touch et quel est son rapport avec Objective-C? Cocoa est l'interface de programmation d'application (API) native d'Apple pour les plates-formes iOS et OS X. Objective-C est le langage qui alimente le cacao. Bien que cet article se concentre principalement sur le langage de programmation Objective-C, nous allons examiner de plus près les API de Cocoa et Cocoa Touch plus loin dans cette série..


Classes, objets et instances

La distinction entre classes, objets et instances est un autre obstacle pour les développeurs qui débutent dans la programmation orientée objet. Une classe est un cast ou un modèle pour la création d'objets, alors que les instances sont des occurrences uniques d'une classe. Un objet est une structure de données qui a un état et un comportement. Malgré la différence subtile entre les objets et les instances, les deux termes sont souvent utilisés de manière interchangeable.

Prenons un exemple: les grille-pain. Avant la fabrication d'un grille-pain, les ingénieurs créent un plan, équivalent à une classe. Chaque grille-pain créé à partir du plan directeur est une instance ou une occurrence unique de la classe. Même si chaque grille-pain est créé à partir du même modèle (classe), ils ont chacun leur propre état (couleur, nombre d'emplacements, etc.) et leur comportement..

Variables d'instance et Encapsulation

L'état d'une instance est stocké dans et défini par ses variables d'instance, ou les attributs de l'objet si vous voulez. Cela nous amène à un autre motif clé de la programmation orientée objet: encapsulation. L'encapsulation signifie que la représentation interne d'un objet est privée et connue uniquement de l'objet. Cela peut sembler une restriction sévère à première vue. Cependant, le résultat est un code modulaire et faiblement couplé.

Illustrons l’encapsulation avec un autre exemple. La vitesse d'une voiture est mesurée par les éléments internes de la voiture, mais le conducteur connaît la vitesse de la voiture en regardant l'indicateur de vitesse. Le conducteur n'a pas besoin de connaître ou de comprendre les éléments internes de la voiture pour connaître sa vitesse. De même, le conducteur de la voiture n'a pas besoin de comprendre le fonctionnement des moteurs pour pouvoir conduire la voiture. Les détails du fonctionnement d'une voiture sont cachés au conducteur. L'état et le comportement de la voiture sont cachés au conducteur et sont accessible via l'interface de la voiture (volant, pédale de frein, tableau de bord, etc.).

Héritage

Un autre paradigme puissant de la programmation orientée objet est héritage de classe. Quand la classe A est un sous-classe de classe B, la classe A hérite des attributs et du comportement de la classe B. On dit que la classe B est la classe ou la super-classe parente de la classe A. L'héritage favorise également la réutilisation du code et la modularité..

Méthodes et propriétés

Les méthodes sont des sous-routines associées à une classe et définissent le comportement d'une classe et de ses instances. Les méthodes d'une classe ont accès aux éléments internes d'une instance et peuvent ainsi modifier l'état de l'instance. En d’autres termes, l’état d’une instance (c’est-à-dire le variables d'instance) est contrôlé par les méthodes d'une instance (c'est-à-dire le méthodes d'instance).

En raison du modèle d'encapsulation, les variables d'instance d'une instance de classe ne sont pas librement accessibles. Au lieu de cela, ils sont accessibles via Getters et les setters, méthodes ayant pour seul but d’obtenir et de définir des variables d’instance. Les propriétés sont une fonctionnalité d'Objective-C qui rend la création d'accesseurs (getters et setters) triviale. Malgré l'utilité des accesseurs, il devient rapidement fastidieux d'écrire des méthodes d'accesseur pour chaque variable d'instance. Nous explorerons les propriétés plus en détail plus tard dans cet article. Pour le moment, considérez les propriétés comme des enveloppes autour de variables d'instance facilitant l'utilisation des variables d'instance via des getters et des setters..


Apprendre par l'exemple

Mettons nos connaissances en pratique en créant un nouveau projet Xcode avec lequel travailler. Créez un nouveau projet dans Xcode en sélectionnant Nouveau> Projet… du Fichier menu.

Comme nous l’avions fait dans l’article précédent, sélectionnez le Outil de ligne de commande modèle de projet dans le Application catégorie sous la OS X section.

Met le Nom du produit à Livres et donnez au projet un nom d'organisation et un identifiant d'entreprise. Pour ce projet, il est important de définir le type de projet sur Fondation. La raison de ce choix deviendra claire plus tard dans cet article.

Indiquez à Xcode où vous souhaitez enregistrer le projet et cliquez sur le bouton Créer bouton. Vous remarquerez peut-être que le projet est différent du projet que nous avons créé pour l'apprentissage C. Prenons un instant pour voir quelles sont les différences..


Aperçu du projet

Le projet contient quelques fichiers et dossiers de plus que l'outil de ligne de commande que nous avons créé dans l'article précédent. En plus de main.m et Livres.1, il y a deux nouveaux dossiers, Fichiers de support et Cadres, chacun contenant un article.

Fichiers de support contient un fichier nommé Livres-Préfixe.pch. le .pch extension de fichier nous dit que c'est un fichier d'en-tête précompilé. Son but deviendra clair plus tard dans cette série.

le Cadres Le dossier contient les cadres auxquels le projet est lié. Qu'est-ce qu'un cadre? Une infrastructure est un ensemble ou un répertoire contenant une bibliothèque, y compris ses ressources, telles que des images et des fichiers d’en-tête. Le concept d'un fichier d'en-tête deviendra clair dans une minute. le Cadres dossier contient actuellement un élément, Foundation.framework.

Lors de la création du projet, vous définissez le type de projet sur Fondation, ce qui signifie que le projet est lié au cadre de la Fondation. Le framework Foundation est un ensemble fondamental de classes Objective-C. Plus tard dans cette série, nous examinerons de plus près le cadre de la Fondation..


Créer une classe

Il est temps de créer votre premier cours. Chaque fois que vous créez un nouveau fichier (Fichier> Nouveau> Fichier… ), une liste de modèles de fichiers vous est présentée. Choisir Cacao du OS X section et sélectionnez le Classe Objective-C modèle pour créer une nouvelle classe Objective-C. Cliquez sur Suivant continuer.

Nommez la nouvelle classe Livre et mettre sa sous-classe à NSObject. Comme nous l’avons vu précédemment, en faisant de la nouvelle classe une sous-classe de NSObject, la nouvelle classe héritera des attributs et du comportement de NSObject. Cela signifie que la nouvelle Livre classe obtient des fonctionnalités gratuitement.

Cliquez sur Suivant continuer et indiquer à Xcode où vous souhaitez enregistrer la nouvelle classe. Assurez-vous de sauvegarder la nouvelle classe quelque part dans votre projet Xcode..

Xcode a ajouté deux nouveaux fichiers au projet, Livre.h et Livre.m. Livre.h est le fichier d'en-tête du Livre classe et expose l'interface de classe comme nous l'avons vu plus tôt. Une interface de classe contient les propriétés et les méthodes de la classe. Elle spécifie également la superclasse de la classe.. Livre.m est le fichier d'implémentation de la classe et définit son comportement en implémentant les méthodes déclarées dans le fichier d'en-tête de la classe.

En tête de fichier

Ouvrir Livre.h et explorer son contenu. À part quelques commentaires en haut, le fichier d’en-tête ne contient que trois lignes de code. La première ligne importe le fichier d'en-tête du framework Foundation. Cela garantit que le Livre la classe a accès aux classes et protocoles déclarés dans le framework Foundation.

#importation 

La deuxième et la troisième ligne forment une paire. En Objective-C, chaque interface de classe commence par @interface et se termine par @fin, qui sont à la fois des directives de compilation, c’est-à-dire des commandes ou des instructions pour le compilateur. le @interface la directive est suivie du nom de la classe, d'un deux-points et de la classe super classe-le cas échéant. Comme nous l’avons vu précédemment, la classe ou superclasse parent est la classe dont elle hérite des attributs et du comportement..

@interface Book: NSObject @end

NSObject est la classe racine de la majorité des classes Objective-C. Les deux premières lettres, NS, se référer à ses origines, NeXTSTEP, comme nous l'avons vu plus haut dans cet article. En héritant de NSObject, les classes se comportent comme les classes Objective-C et héritent d'une interface basique avec le système d'exécution.

Fichier d'implémentation

Avant de modifier le Livre classe, prenons un rapide pic Livre.m, le fichier d'implémentation de la classe. Au lieu d’importer le framework Foundation, le fichier d’implémentation importe le fichier d’en-tête du fichier Livre classe. Pourquoi est-ce nécessaire? Le fichier d'implémentation doit savoir quelles propriétés et quelles méthodes sont déclarées dans le fichier d'en-tête avant de pouvoir implémenter le comportement (c'est-à-dire les méthodes) de la classe. La déclaration d'importation est suivie de l'implémentation de la classe, indiquée par @la mise en oeuvre et @fin.

Ajout de propriétés et de méthodes

le Livre La classe n'est pas très utile dans son implémentation actuelle. Rendez-vous dans le fichier d'en-tête et ajoutez trois propriétés année, Titre, et auteur, et ajoutez une méthode nommée bookInfo.

Les propriétés sont déclarées avec le @propriété mot-clé et peut être déclaré n'importe où dans la classe @interface bloc. le @propriété mot-clé est suivi du type et du nom de la propriété. N'oubliez pas l'astérisque devant le Titre et auteur propriétés, car un objet Cocoa est toujours référencé comme un pointeur.

#importation  @interface Book: NSObject @property int year; @property NSString * title; @property NSString * author; - (NSString *) bookInfo; @fin

La déclaration de méthode ressemble légèrement à un prototype de fonction, mais il existe un certain nombre de différences clés. La déclaration de méthode commence par un signe moins, indiquant qu'il s'agit d'une méthode d'instance. Les méthodes de classe sont précédées du signe plus. Le signe moins est suivi du type de retour de la méthode entre parenthèses, une instance de NSString, et le nom de la méthode. La déclaration de méthode se termine par un point-virgule.

Je suis sûr que vous vous demandez quoi NSString est et pourquoi il doit être référencé comme un pointeur. le NSString La classe est membre du framework Foundation. Il déclare l'interface d'un objet qui gère une chaîne immuable. Dans l'article précédent, nous avons vu qu'une chaîne en C peut être représentée par un tableau de caractères et c'est exactement ce que le NSString la classe fait, il gère un tableau de caractères sous le capot. L'avantage d'utiliser NSString est-ce qu'il est beaucoup plus facile de travailler avec des chaînes.

Exécution bookInfo

Maintenant que nous avons déclaré le bookInfo méthode dans le fichier d'en-tête de la classe, il est temps de l'implémenter dans le fichier d'implémentation de la classe. Ouvrir Livre.m et ajoutez l'extrait de code suivant quelque part dans le @la mise en oeuvre bloc. Avant de casser la mise en œuvre de bookInfo vers le bas, nous devons d’abord parler de la messagerie objet.

- (NSString *) bookInfo NSString * bookInfo = [chaîneNSString stringWithFormat: @ "% @ a été écrit par% @ et publié dans% i", self.title, self.author, self.year]; retour bookInfo; 

Messagerie objet

Nous savons déjà que le comportement d'une classe est défini par ses méthodes. Pour appeler une méthode sur un objet, un message est envoyé à l'objet. Examinez l'extrait de code suivant pour comprendre ce concept. Découpons ligne par ligne. Dans la première ligne, nous déclarons une nouvelle chaîne et lui attribuons une chaîne constante en l'enveloppant de guillemets doubles et en la précédant d'un @ signe.

NSString * string = @ "Ceci est une chaîne de caractères."; int longueur = [longueur de chaîne]; NSLog (@ "La longueur de la chaîne est% i. \ N" longueur);

Dans la deuxième ligne, nous envoyons un message de longueur à l'occurrence de chaîne. En d'autres termes, nous appelons la méthode longueur sur l'occurrence de chaîne et la méthode retourne un entier. L'entier est attribué à la longueur variable de type int. Dans la dernière ligne, nous enregistrons la variable de longueur dans la console en appelant le NSLog fonctionner comme nous l'avons vu dans l'article précédent.

Vous ferez beaucoup de messages à des objets, il est donc important de comprendre la syntaxe. Même si la syntaxe semble étrange si vous débutez avec Objective-C, ce n'est pas si difficile à comprendre. Entre les crochets se trouvent l'objet à gauche et le nom du message ou de la méthode à droite.

[message d'objet];

Les méthodes qui acceptent les arguments sont un peu différentes, mais la syntaxe générale est identique. le NSString La classe, par exemple, a une autre méthode nommée substringFromIndex:. Les deux points à la fin du nom indiquent que cette méthode accepte un argument. L'appel de cette méthode sur une chaîne ressemble à ceci:

NSString * substring = [chaîne substringFromIndex: 5];

Objective-C est connu pour ses noms de méthode longs et détaillés. Examinez l'exemple suivant, qui inclut un nom de méthode avec plusieurs arguments. Vous devez admettre que le nom de la méthode indique clairement ce que fait la méthode. Le nom de la méthode est divisé en morceaux, chaque morceau acceptant un argument. La messagerie d'objet va vraiment couler une fois que nous commencerons à travailler avec le SDK iOS.

NSString * anotherString = [chaîne stringByPaddingToLength: 5 withString: @ "une chaîne" startingAtIndex: 2];

Avant de poursuivre, nous devons revoir la mise en œuvre de bookInfo. L'implémentation de la méthode commence par répéter la déclaration de la méthode. Le point-virgule final est remplacé par une paire d'accolades qui enveloppent la mise en œuvre de la méthode. Nous déclarons d'abord une nouvelle chaîne, bookInfo, et lui assigner une nouvelle chaîne, créée avec les attributs de notre instance de livre (Titre, auteur, et année). À la fin de bookInfo méthode, nous retournons la nouvelle chaîne, bookInfo, parce que c'est ce que la méthode attend, une chaîne comme type de retour.

Trois choses nécessitent des éclaircissements. Tout d'abord, la méthode stringWithFormat: est une méthode de classe et non une méthode d'instance. Nous le savons parce que la méthode est appelée sur la classe elle-même, NSString, pas sur une instance de la classe. Les méthodes de classe sont courantes dans les langages de programmation orientés objet. Deuxièmement, le spécificateur de format pour un objet est représenté par le @ symbole (précédé du signe de pourcentage). Tous les deux Titre et auteur sont des objets-chaînes pour être précis. Troisièmement, le soi mot-clé fait toujours référence à l'instance de la classe. Dans ce cas, soi se réfère à la Livre instance à laquelle la méthode bookInfo fait parti.

Accesseurs revisités

Si vous avez travaillé avec d'autres langages orientés objet, accéder aux variables d'instance dans Objective-C peut être source de confusion. Nous n'accédons pas directement à une variable d'instance lorsque nous écrivons self.title. Ce n’est rien de plus qu’un raccourci pour [titre personnel]. Ce dernier signifie que nous utilisons la méthode getter pour demander à l’instance la variable d’instance nommée Titre. Il en va de même pour la définition d'une variable d'instance. Jetez un coup d'œil à l'extrait de code suivant. Comme vous pouvez le voir, l’utilisation de self.title n'est rien de plus que du sucre syntaxique.

// Cette affectation… self.title = @ "The Hobbit"; //… est équivalent à… [self setTitle: @ "The Hobbit"];

identifiant, néant, et NUL

identifiant

Avant de commencer à utiliser le Livre classe, je veux parler de quelques mots-clés qui déroutent les gens de temps en temps. Chaque fois que vous souhaitez stocker un objet sans définir explicitement son type, vous utilisez le identifiant type de données, qui est également le type par défaut pour les déclarations de retour et d'argument pour les méthodes Objective-C.

Le pouvoir et l'utilité de la identifiant type de données va beaucoup plus loin, cependant. le identifiant Le type de données est un composant clé du typage dynamique et de la liaison dynamique d'Objective-C. Il est important de comprendre que le identifiant le type de données ne contient aucune information sur l'objet lui-même autre que le fait qu'il s'agisse d'un objet.

En Objective-C, chaque objet sait à quelle classe il appartient (à travers un est un variable) et cela est critique. Pourquoi donc? L’un des points forts d’Objective-C est son typage dynamique, ce qui signifie que la vérification du type est effectuée au moment de l’exécution au lieu de la compilation..

Cependant, depuis le identifiant le type de données n'indique rien au compilateur sur la classe à laquelle appartient l'objet, l'objet lui-même doit fournir cette information au compilateur.

Gardez à l'esprit qu'il est parfaitement acceptable de taper statiquement un objet dans Objective-C en spécifiant explicitement la classe d'un objet au lieu d'utiliser le paramètre identifiant Type de données.

Reliure dynamique

Cela nous amène à un autre composant essentiel du moteur d'exécution Objective-C, la liaison dynamique. En Objective-C, une différence importante entre les fonctions et les messages est qu'un message et l'objet récepteur ne sont pas unis jusqu'à l'exécution.

Qu'est-ce que cela signifie et pourquoi est-ce important? Cela signifie que la méthode appelée en réponse à un message envoyé à un objet est déterminée au moment de l'exécution, lorsque le message et l'objet sont connus. C'est ce qu'on appelle la liaison dynamique.

néant et NUL

En Objective-C, le mot clé néant est défini comme un nul objet, c'est-à-dire un identifiant avec une valeur de 0. Sous le capot, il n'y a pas de différence entre néant, Néant, et NUL, et il est possible d'envoyer des messages à chacun d'eux sans exception..

La convention est d'utiliser néant pour les objets, Néant pour les cours, et NUL autrement. Être capable d'envoyer des messages à néant, Néant, et NUL a des avantages, mais il a aussi des inconvénients. Pour plus d'informations sur néant, Néant, et NUL, jetez un oeil à cette question sur Stack Overflow.


Création d'objets

Ouvrir main.m et ajoutez une instruction d'importation pour importer le fichier d'en-tête du Livre classe. Au lieu d'utiliser des crochets, nous utilisons des guillemets pour importer le fichier d'en-tête du Livre classe. Les guillemets doubles sont utilisés pour les fichiers locaux, alors que les chevrons sont utilisés pour les inclusions globales, en utilisant le chemin d’inclusion du projet..

#importation  #import "Book.h"

Immédiatement en dessous de la NSLog appel, ajoutez le fragment de code suivant pour créer une instance du Livre classe.

Book * book1 = [[Book alloc] init]; book1.title = @ "Le Hobbit"; book1.author = @ "JRR Tolkien"; book1.year = 1937;

Dans la première ligne, nous déclarons une variable de type Livre et l'initialiser. C'est un bon exemple pour illustrer les appels de méthodes imbriquées. La première méthode appelée sur le Livre la classe est allouer. Les détails de cet appel ne sont pas importants. L'essentiel est que la mémoire est allouerated pour le nouvel objet et l'objet est créé.

En raison de l'imbrication des appels, le init La méthode est appelée sur le nouvel objet créé par le allouer méthode. le init méthode initialise le nouvel objet, en le configurant et en le rendant prêt à être utilisé. le init La méthode retourne l'instance et, dans notre exemple, l'assigne à la book1 variable.

Les trois prochaines lignes doivent maintenant être familières. Nous définissons le titre, l'auteur et l'année de publication du nouveau livre..

Créons un autre livre et ajoutons les deux livres à un tableau Objective-C. La création du deuxième livre n'est pas nouvelle. La seule différence est que nous avons utilisé explicitement les paramètres de la classe pour définir les variables d'instance de la nouvelle instance..

Book * book2 = [[Book alloc] init]; [book2 setTitle: @ "La communauté de l'anneau"]; [book2 setAuthor: @ "JRR Tolkien"]; [book2 setYear: 1954]; NSArray * books = [[NSArray alloc] initWithObjects: book1, book2, nil];

Dans la dernière ligne, nous créons une instance de NSArray, une autre classe du framework Foundation. le NSArray class est un tableau pouvant stocker une liste ordonnée d'objets. Comme nous l'avons fait avec les instances de livre, nous allouons de la mémoire et initialisons le nouveau tableau.

Au lieu d'appeler init, cependant, nous appelons initWithObjects:initWithObjects: est un initialiseur désigné, ce qui signifie que c'est un init méthode avec quelques cloches et sifflets supplémentaires pour faciliter l'initialisation de l'objet.

initWithObjects: accepte n'importe quel nombre d'objets que vous souhaitez stocker dans le tableau. La liste des objets doit toujours se terminer par néant.

Mélanger C et Objective-C

J'ai déjà mentionné à plusieurs reprises qu'Objective-C est un sur-ensemble strict de C et que nous pouvons combiner librement C et Objective-C. Voyons comment cela fonctionne. Nous commençons par utiliser un simple sinon instruction pour vérifier si le tableau contient des objets. En envoyant au tableau un message de compter, il retournera le nombre d'objets qu'il contient.

Si le tableau contient des objets, nous utilisons un pour boucle pour parcourir les objets dans le tableau. A chaque itération, nous demandons au tableau l'objet à l'index je et envoyer l'objet-une instance du Livre classe-un message de bookInfo. Comme nous l'avons vu plus tôt, bookInfo retourne une instance de NSString, que nous connectons à la console.

if ([nombre de livres]> 0) pour (int i = 0; i < [books count]; i++)  Book *aBook = [books objectAtIndex:i]; NSLog(@"%@", [aBook bookInfo]);  

Conclusion

Je suis sûr que vous êtes un peu dépassé par Objective-C. C'est normal. Même si Objective-C n’est rien de plus qu’une mince couche au-dessus du langage C, il se passe beaucoup de choses.

Bien qu'Objective-C soit plus complet que ce qui est décrit dans cet article, vous connaissez maintenant les bases et êtes prêt à commencer à utiliser le SDK iOS. Dans le prochain article, nous examinerons le SDK iOS et explorerons ses différents composants..