Introduction
Sur cette page, je vous invite à découvrir les outils de développement sous Mac OS X à travers le développement d’une petite application graphique. Dans le cadre du développement d’une application pour iPhone qui doit consommer un service web, j’ai utilisé l’utilitaire WSMakeStubs en ligne de commande pour générer les stubs en Objective-C. Je vous propose de créer une petite interface graphique pour WSMakeStubs.
Prérequis
Outils de développement
Pour développer sous Mac OS X, il est impératif d’installer les Developer Tools, fournis gratuitement sur le DVD d’installation de Mac OS X. Toutefois, je vous recommande d’obtenir la dernière version sur le site d’Apple. Après installation, un répertoire Developer apparaît à la racine du système : il contient tous les outils de développement dont vous avez besoin pour développer n’importe quelle application pour Mac… et pour iPhone.
Connaissances
Bien qu’on puisse programmer avec plusieurs langages différents sous Mac OS X (Java, Python, C/C++, …), le langage de prédilection reste l’Objective-C, qui est une sorte de C++ amélioré, développé par Apple mais disponible sous d’autres plates-formes. En fait, le plus intéressant dans Objective-C n’est pas le langage en lui-même, mais c’est surtout l’ensemble des frameworks (librairies, ou encore API) mis à disposition par Apple. Cet ensemble s’appelle Cocoa.
Avant de continuer, et si vous ne connaissez pas Objective-C ni Cocoa, je vous recommande vivement de consulter les liens suivants, sur le site d’Apple (en anglais) :
- découverte d’Objective-C
- passer de C++ à Objective-C (excellent document !)
- les principaux frameworks de Cocoa
Vous devez aussi connaître l’architecture MVC, les applications graphiques Cocoa étant fortement basées dessus.
Enfin, vous devez avoir une bonne connaissance de l’anglais technique, car il n’existe pas énormément de documentation en français.
XCode
Xcode est l’incontournable IDE pour coder des applications pour Mac OS X et pour iPhone. Voici quelques fonctionnalités intéressantes de Xcode, que l’on retrouve d’ailleurs dans la plupart des autres environnements de développement :
- gestion de projets
- snapshots de projets
- connexion avec des systèmes de gestion de code source (SCM)
- autocomplétion et colorisation du code
- refactoring
- débogueur intégré
Xcode est plein de qualités, il marche bien et il est performant. Toutefois, la prise en main peut paraître déroutante, pour peu que l’on soit habitué à d’autres IDE. C’est une ergonomie à la Apple, et pour développeurs, qui plus est ! Sachez toutefois que les dernières versions de Photoshop pour Mac ont été développées avec Xcode, ainsi que les applications pour iPhone (et ce ne sont que des exemples).
Pour démarrer Xcode, rendez-vous dans le répertoire /Developer/Applications/ avec le Finder et lancez Xcode.
Fermez cette fenêtre. Je vous conseille d’aller tout de suite dans les préférences de Xcode (cmd+,) pour choisir, dans la première section, le layout All-In-One, beaucoup plus pratique à mon avis.
Allez ensuite dans le menu File > New Project… puis sélectionnez Cocoa Application dans Mac OS X > Application.
Dans notre exemple, l’application s’appelle WSStubCreator. Donnez ce nom à votre application puis validez. Vous arrivez alors sur la vue principale de Xcode.
Il y a des éléments (fichiers) qui sont présents sur cette copie d’écran que vous n’avez pas encore. Ne vous inquiétez pas, nous allons les créer bientôt.
Création du contrôleur
Une application graphique Cocoa utilise l’architecture MVC. Dans notre application WSStubsCreator, nous n’avons pas de données à manipuler : la partie Modèle de MVC n’interviendra donc pas dans notre exemple. Commençons par créer le contrôleur :
- Sélectionnez le dossier Classes dans l’arborescence du projet
- Clic droit puis Add > New File…
- Sélectionnez Objective-C class dans Mac OS X > Cocoa
- Nommez cette classe MainController
- Validez
Vous voilà avec une belle classe vide. En Objective-C, toutes les classes que vous créez doivent hériter d’une autre classe. Si vous ne savez pas ou si vous pensez que votre classe ne doit pas hériter d’une autre, faites-la hériter de NSObject.
@interface MainController : NSObject { } @end |
Nous allons maintenant passer à la réalisation de l’interface graphique. Dans l’arborescence de gauche de votre projet, ouvrez le dossier NIB Files et double-cliquez sur MainMenu.xib. InterfaceBuilder se lance alors.
InterfaceBuilder
Plusieurs fenêtres apparaissent à l’écran.
Les composants de l’application
Cette fenêtre liste les composants principaux qui constituent votre application. On remarque qu’on y trouve le menu principal de l’application (MainMenu). On peut éditer ce menu graphiquement depuis InterfaceBuilder. On aperçoit aussi le First Responder : il représente le premier élément qui aura le focus au lancement de l’application. Parmi tous ces éléments, nous ne toucherons qu’à l’élément Window qui représente la fenêtre principale de l’application.
La fenêtre d’édition
C’est la fenêtre dans laquelle nous allons placer les éléments graphiques qui composent notre application : zones de saisie, boutons, … Le système de coordonnées sous Mac OS X est différent de celui de la plupart des autres systèmes : le point (0,0) est en bas à gauche de la fenêtre, souvent il est en haut à gauche. Think different!
L’inspecteur
Il permet de définir les différentes propriétés des éléments sélectionnés dans la fenêtre d’édition. Il est divisé en 7 sections, accessibles via les icônes en haut de la fenêtre :
- les attributs principaux
- les effets graphiques (Core Animation)
- la taille et le positionnement
- les bindings
- les connections
- l’identité
- des informations additionnelles pour AppleScript
Nous reviendrons un peu plus tard sur les différentes sections que nous utiliserons au cours du développement de notre application.
Le navigateur d’objets et de média
Il permet de naviguer parmi les différents éléments utilisables pour composer l’interface graphique de l’application. Il est divisé en 2 grandes sections :
- les objets : ce sont les éléments graphiques comme les zone de saisie, les boutons, …
- les média : ce sont les images, sons, … que l’ont peut inclure dans l’application.
Nous n’utiliserons que les objets pour notre application. Les objets sont rangés dans plusieurs grandes catégories : Cocoa, Interface Builder Kit, Web Kit, Address Book, Automator, DiscRecording, Image Kit, Open Scripting Kit, PDFKit, QuickTime Kit, Quartz Composer et Custom Objects. Nous nous intéresserons principalement aux éléments de la catégorie Cocoa, elle même divisée en trois rubriques :
- Application : fenêtres, barres d’outils, menus,
- Objects & Controllers : liens entre l’interface graphique et la logique de l’application,
- Views & Cells : éléments graphiques avec lesquels interagit l’utilisateurs.
Construction de l’interface graphique
De quoi avons-nous besoin ? Nous cherchons à réaliser une interface graphique à l’utilitaire WSMakeStubs. Ouvrons un Terminal (dans le Finder : Applications > Utilitaires > Terminal) puis exécutons WSMakeStubs.
iMac:~ Fred$ WSMakeStubs
WSMakeStubs [-x lang] [-dir directory] [-name fname] { -url | -file }
WSMakeStubs nous répond qu’il a besoin de plusieurs arguments :
- le langage dans lequel créer les stubs (-x)
- le répertoire de destination des fichiers (-dir)
- le nom des fichiers à générer (-name)
- l’URL du descripteur WSDL (-url)
Nous allons offrir à l’utilisateur le choix :
- du répertoire de destination
- du nom des fichiers à générer
- de l’URL du descripteur WSDL
Le langage des fichiers générés sera fixé en dur dans le code à ObjC (pour Objective-C).
Glissons donc trois éléments Label et trois éléments Text Field, disponibles dans Views & Cells > Inputs & Values. Aidez-vous des guides de placement très pratiques pour aligner vos éléments. Editez les libellés et ajuster l’alignement du texte dans les Label. Modifiez la taille et le titre de la fenêtre. Nous avons aussi besoin d’un Push Button pour lancer la création des stubs, disponible dans Views & Cells > Buttons.
Vous devez arriver à une interface qui ressemble à ceci :
Il va maintenant falloir relier ces éléments graphiques à notre contrôleur.
Liaison des éléments graphiques au contrôleur
IBOutlet
Nous allons référencer notre contrôleur MainController dans InterfaceBuilder. Pour cela :
- glissez un élément Object (disponible dans Objects & Controllers) dans la fenêtre qui liste les composants de l’application.
- sélectionnez ce nouvel élément et, dans la section Identity de l’inspecteur, définissez le nom de la classe de votre contrôleur : MainController.
- dans le menu principal de InterfaceBuilder, choisissez File > Read Class Files… puis sélectionner le fichier de définition de votre classe MainController.h.
Retournez dans Xcode, puis éditez MainController.h pour ajouter 3 outlets :
#import @interface MainController : NSObject { IBOutlet NSTextField* urlField; IBOutlet NSTextField* nameField; IBOutlet NSTextField* dirField; } @end |
Un outlet permet de référencer un élément graphique dans votre code : c’est une sorte de passerelle qui vous permet d’accéder à un élément graphique que vous avez disposé dans InterfaceBuilder.
D’un point de vue syntaxique, IBOutlet
est une macro C qui ne fait rien, mais qui permet à InterfaceBuilder de repérer les connexions lorsqu’il lit la classe de votre contrôleur (vous vous souvenez du Read Class Files… ?).
Retournez dans InterfaceBuilder et, dans le menu principal, choisissez File > Reload All Class Files. Dans l’inspecteur de l’objet Main Controller, vous devez voir apparaître les 3 outlets (dans la section Identity). On peut maintenant connecter graphiquement les éléments à ces outlets.
Faites un clic droit sur Main Controller dans la fenêtre des composants de l’application puis, sans relâcher le bouton de la souris, glissez le pointeur sur une des zones de texte dans votre fenêtre d’édition. L’élément est alors mis en évidence et son type est affiché.
Relâcher alors le bouton droit de la souris. Un menu apparaît dans lequel vous devez choisir à quelle variable de votre MainController vous voulez connecter ce champ texte. Dans l’exemple de l’image ci-dessus, il faut choisir urlField
.
Effectuez cette action pour chacun des trois champs : urlField
, dirField
et nameField
.
IBAction
Concernant les actions que l’utilisateur peut demander à votre application, via un bouton par exemple, il s’agit de créer des méthodes dans la classe du contrôleur et de les identifier avec la macro IBAction
, afin de les référencer dans InterfaceBuilder. Nous allons donc créer une méthode createStubs:sender
dans notre contrôleur.
Dans MainController.h :
#import @interface MainController : NSObject { IBOutlet NSTextField* urlField; IBOutlet NSTextField* nameField; IBOutlet NSTextField* dirField; } -(IBAction)createStubs:(id)sender; @end |
Toutes les méthodes de votre contrôleur qui doivent être connectées à une action utilisateur (toutes les méthodes précédées de IBAction
, donc) doivent accepter un seul argument de type id
(généralement nommé sender
) qui représente l’élément graphique déclencheur de l’action.
Retournez dans InterfaceBuilder, puis File > Reload All Class Files. Faites un clic droit sur le bouton Créer puis, sans relâcher la souris, glissez le pointeur sur Main Controller. Relâcher le bouton de la souris puis choisissez la méthode du contrôleur à rattacher au bouton.
Notez que la manipulation pour connecter un IBOutlet
est l’inverse de celle pour connecter une IBAction
: pour connecter un IBOutlet
, vous partez du contrôleur puis vous choisissez à quel élément graphique relier quel outlet, tandis que pour l’IBAction
, vous partez d’un élément de l’interface graphique vers le contrôleur et choisissez la méthode à connecter.
Code de création des stubs
Nous allons maintenant coder l’appel à WSMakeStubs dans notre contrôleur. Pour cela, retournez dans Xcode et éditez le fichier MainController.m.
Nous allons utiliser la class NSTask pour lancer une commande externe avec des arguments.
- (IBAction)createStubs:(id)sender { NSArray *arguments = [NSArray arrayWithObjects: @"-x", @"ObjC", @"-url", [urlField stringValue], @"-name", [nameField stringValue], @"-dir", [dirField stringValue], nil]; [[NSTask launchedTaskWithLaunchPath:@"/Developer/usr/bin/WSMakeStubs" arguments:arguments] waitUntilExit]; } |
On utilise ici la classe NSArray et sa méthode statique arrayWithObjects:
qui permet de créer un tableau à partir des objets listés en arguments ; ici on crée un tableau de chaînes de caractères (NSString) soit codées en dur (nom des arguments et valeur de l’argument -x) soit issues des champs texte urlField
, nameField
et dirField
. Attention à ne pas oublier le @
qui permet d’écrire une chaîne NSString !
Exécution et test du programme
Cliquez sur Build and Go dans Xcode pour compiler et lancer votre programme.
Comme service web gratuit, pour pouvez utiliser celui de Google, dont l’URL du descripteur WSDL est la suivante : http://api.google.com/GoogleSearch.WSDL. Entrez le répertoire de destination (par exemple /Users/Fred/Desktop) puis le nom des fichiers (par exemple Google). Cliquez sur le bouton Créer et admirez le code Objective-C qui a été généré pour vous !
Améliorer l’application
Bien sûr, cette application est perfectible ! Voici quelques éléments pour l’améliorer, mais je vous laisse les coder pour vous entraîner :
- ajouter un bouton qui permet de choisir le dossier de destination (utiliser la classe NSOpenPanel)
- désactiver le bouton pendant l’exécution du processus de création des stubs (utiliser la méthode
setEnabled:
du NSButton, méthode héritée de NSControl).
Allez plus loin
Si vous souhaitez aller plus loin, vous pouvez lire les documents suivants :