Mouviciel

Création d'applications pour Mac OS X

Les coulisses d'un développeur Mac

La rubrique « Technique » contient les articles affichés ci-dessous.

Délégation en Cocoa, être et avoir — Première partie

Publié le jeudi 4 septembre 2008, 6 commentaires

De nombreuses classes en Cocoa ont la possibilité de modifier leur comportement grâce au mécanisme de la délégation : Une instance d'une telle classe peut accueillir un objet qui souhaite être son délégué. Elle lui envoie alors certains messages, nommés méthodes déléguées, que cet objet sera libre de traiter.

Ainsi il y a deux facettes à la délégation :

Ce deuxième point sera le sujet de la deuxième partie.

Être un objet délégué

La plupart du temps, le développeur s'intéresse à enrichir ou à personnaliser le comportement d'un objet qui accepte d'avoir un objet délégué. Par exemple, il souhaitera que la fenêtre principale de son application soit redimensionnée selon des règles qu'il aura fixées.

Justement la classe NSWindow dispose de la méthode déléguée -windowWillResize:toSize: qui est envoyée à l'objet délégué de la fenêtre chaque fois que la fenêtre s'apprête à être redimensionnée. Il suffit que l'objet délégué réponde à cette méthode, et il pourra mettre son grain de sel dans le redimensionnement de la fenêtre.

Voici comment cela se passe.

Nous allons réaliser ensemble une petite application Cocoa dont l'unique fonction est de conserver les proportions de sa fenêtre lorsqu'elle est redimensionnée.

Tout d'abord, créez dans Xcode un nouveau projet d'application Cocoa. Nommez-le Delegate. Ajoutez une classe à ce projet : Menu File—New File..., puis Objective-C class. Nommez-la windowController.m et choisissez de créer aussi windowController.h. Il s'agit du contrôleur de la fenêtre, qui agira pour elle en qualité de délégué.

Ensuite, ouvrez le fichier qui décrit l'interface graphique MainMenu.xib (ou MainMenu.nib si vous n'avez pas une version récente d'Xcode). Nous allons y ajouter le contrôleur que nous venons de créer et le déclarer comme délégué de la fenêtre principale. Si ce n'est pas déjà fait, ouvrez la palette Library (cmd-shift-L) et la palette Inspector (cmd-shift-I).

Dans la palette Library trouvez l'élément Object de classe NSObject (c'est un cube bleu sans sphère autour) et faites-le glisser dans la fenêtre nommée MainMenu.xib (English). Cette fenêtre contient la description complète de l'interface graphique de l'application.

Assurez-vous que l'objet que vous venez de faire glisser est sélectionné, puis dans la palette Inspector choisissez l'onglet Identity (c'est un signe i dans un cercle). Dans la rubrique Class Identity Choisissez la classe windowController (c'est la classe que nous avonc créée, normalement elle est à la fin de la liste déroulante).

À ce stade, nous venons de créer une instance de windowController directement dans l'interface graphique. Nous allons maintenant lier cet objet à la fenêtre de l'application en le déclarant délégué de la fenêtre. Cela se passe encore dans Interface Builder

À l'intérieur de la fenêtre MainMenu.xib (English) localisez la fenêtre de l'application, elle s'appelle Window (Window). Réalisez un ctrl-drag depuis son icône jusque vers l'objet windowController (placez la souris sur l'icône de la fenêtre de l'application, pressez la touche ctrl puis le bouton de la souris, et sans relâcher déplacez la souris jusque sur l'icône de notre nouvel objet, maintenant relâchez).

Un petit menu noir semi-transparent apparaît, il est intitulé Outlets et contient un unique élément nommé delegate. Nous y voici ! Sélectionnez cet élément. Et voilà : notre windowController est devenu le délégué de la fenêtre de l'application. Sauvez MainMenu.xib (cmd-S) et revenez à Xcode.

Vérifions que cela marche comme nous le souhaitons : faisons en sorte que notre délégué accomplisse sa tâche de délégué. Modifiez le fichier windowController.m de la façon suivante (les modifications sont en gras) :

//
//  windowController.m
//  Delegate
//
//  Created by mouviciel on 04/09/08.
//  Copyright 2008 Mouviciel. All rights reserved.
//

#import "windowController.h"


@implementation windowController

- (NSSize)windowWillResize:(NSWindow *)window
                    toSize:(NSSize)proposedFrameSize
{
    NSLog(@"La taille demandée est: %@",
          [NSValue valueWithSize:proposedFrameSize]);
    return proposedFrameSize;
}

@end

Sauvez (cmd-S), compilez et lancez (Build and Go). Si la console n'apparaît pas (c'est une fenêtre avec à l'intérieur un texte semblable à : [Session started at 2008-09-04 22:16:09 +0200.]), pressez cmd-shift-R. Essayez de redimensionner la fenêtre de notre application Delegate et observez la console. Si tout se passe comme prévu, vous devriez voir une série de messages de la forme :

[Session started at 2008-09-04 22:21:31 +0200.]
2008-09-04 22:21:34.264 Delegate[20657:10b] Taille: NSSize: {482, 382}
2008-09-04 22:21:34.280 Delegate[20657:10b] Taille: NSSize: {485, 382}
2008-09-04 22:21:34.297 Delegate[20657:10b] Taille: NSSize: {491, 382}

Félicitations ! Vous venez de créer un objet délégué qui agit pour le compte d'un objet délégateur. Je vous laisse le soin de faire évoluer cette application de telle sorte que la largeur de la fenêtre soit exactement le double de sa hauteur (un indice : la taille proposedFrameSize est la taille demandée par l'utilisateur qui redimensionne la fenêtre, la valeur retournée par la méthode est la taille qui sera réellement donnée à la fenêtre).

Vous l'avez sans doute compris, la deuxième partie illustrera l'autre facette de la délégation, à savoir : avoir un objet délégué.

Contrôle de versions et Xcode - Première partie

Publié le jeudi 21 août 2008, aucun commentaire

Parmi les outils que je trouve essentiels en informatique, j'en connais au moins deux qui sont peu ou mal enseignés. Il s'agit du test et du contrôle de versions. Pour l'heure, je garde le test de côté et je vous parlerai ici du contrôle de versions. Ce premier article évoque les bénéfices qu'on peut attendre d'un outil de contrôle de version. Le prochain article détaillera les étapes à suivre pour activer un tel outil dans Xcode.

Le contrôle de versions pour quoi faire ?

Vous est-il déjà arrivé d'avoir écrit un morceau de code dont vous êtes très fier, mais qui vous laisse l'impression qu'il pourrait être amélioré ? Qu'avez-vous fait ensuite ? Vous avez peut-être poursuivi sur la lancée, modifié une ligne ici, ajouté une fonction là, revu un peu l'architecture en prévision d'autres modifications dont vous venez d'avoir l'idée... Et puis patatras, plus rien ne marche ! Bien sûr, loi de Murphy oblige, vous n'aviez pas sauvegardé votre travail initial. Il ne vous reste plus qu'à revenir en arrière petit à petit ou bien tout recommencer depuis le début.

Si vous êtes plus prudent, vous aurez sans doute sauvé votre travail régulièrement. Peut-être les premières fois en écrasant les anciennes modifications par les nouvelles, jusqu'au jour où vous vous apercevez que votre modification en cours ne marche pas, ni celle que vous avez sauvée. La version correcte était juste un peu plus ancienne... Peut-être décidez-vous alors de faire des sauvegardes successives dans des dossiers dont le nom inclut la date ou un quelconque repère unique, de façon à conserver toutes vos modifications. Dans ce dernier cas, vous n'êtes plus très loin du contrôle de versions et cet article vous intéressera certainement.

Un outil de contrôle de version fait exactement cela : conserver et retrouver l'historique des modifications du code source d'un logiciel. Il le fait de façon un peu plus élaborée qu'une collection de dossiers datés. D'abord, les versions successives ne sont pas sauvées in extenso : seules les modifications depuis la version précédente sont archivées. Cela permet de garder l'historique en utilisant une quantité de mémoire très faible.

Ensuite, l'historique n'est pas nécessairement linéraire. Il est possible de faire plusieurs évolutions parallèles à partir d'une même version antérieure. L'historique devient un arbre avec son tronc et ses branches, c'est un vocabulaire couramment utilisé parmi les outils de contrôle de versions. Quel est l'intérêt de cette pratique ?

Supposons que je sois l'auteur d'un super logiciel que j'ai baptisé fort à propos MonSuperLogiciel. La première version a déjà beaucoup de succès et j'ai commencé à développer des nouvelles fonctionnalités pour la deuxième version qui sera encore plus géniale. Et voici qu'un utilisateur découvre une erreur dans la première version. Le système de branches de l'outil de contrôle de versions me permet de corriger l'erreur de la version 1.0 et de rapidement proposer une version 1.1. Pendant ce temps je peux continuer à travailler sur la version 2.0, elle aussi issue de la version 1.0.

Enfin, un outil de contrôle de versions offre la possibilité inverse, à savoir réunir les modifications développées dans deux branches parallèles. L'analogie botanique trouve ici ses limites et le mot consacré est issu de l'anglais : l'opération est généralement appelée merge. Pour poursuivre sur mon exemple, l'intérêt du merge est que je peux intégrer la correction de l'erreur réalisée dans la version 1.1 de MonSuperLogiciel dans la branche consacrée au développement de la version 2.0.

Si vous souhaitez vous plonger un peu plus dans les arcanes du contrôle de versions, je vous invite à lire (en anglais) le dossier Source Control HOW TO sur le blog d'Eric Sink.

Quels outils de contrôle de version pour Xcode ?

De nombreux outils de contrôle de version existent. Une liste incomplète existe sur Wikipédia. Certains sont plus en vogue ces temps-ci, comme par exemple Git ou Mercurial, pour lequel un petit guide pour Mac en français existe sur le blog Cocoa.fr. Mais si vous travaillez avec Xcode votre choix est réduit à trois : CVS, Subversion et Perforce.

Dans mon prochain article vous saurez pourquoi j'ai choisi Subversion et je vous expliquerai comment l'activer pour vos projets Xcode.

Archive

Rubriques

Abonnement