Les variables des objets Cocoa
La dernière fois, nous avons évoqué la relation entre les objets de Cocoa et ceux d’AppleScript. La hiérarchie des objets, l’ordonnancement en classes et sous-classes, est fondamentale pour créer une équivalence (une “carte”) entre votre outil de script et votre application.
Cette carte (NdT: map en anglais) se trouve dans le fichier scriptSuite, qui est une liste de propriétés XML, située dans le dossier ressources du projet. Outre le fichier scriptSuite, nous avons aussi créé un fichier scriptTerminology qui sert à déterminer la syntaxe du dialecte que vous allez fournir. Jusqu’alors, comme on me l’a fait remarquer, l’anglais est la seule langue comprise mais le principe sera le même avec n’importe quelle autre langue quand elle sera supportée.
Accéder à des variables encapsulées dans des objets Cocoa
Aujourd’hui, nous allons voir comment accéder aux variables d’instance encapsulées dans les objets Cocoa et nous allons explorer, en partie, la Core Text Suite fournit grâcieusement avec Cocoa.
Vous vous rappelez peut-être de la description des objets que j’ai donnée dans un précédent article, les objets sont blocs de code qui contiennent des variables servant à stocker l’information et des méthodes qui sont les actions associées à l’objet.
Les variables sont généralement divisées en deux sous-ensembles, les variables de classe et les variables d’instance. Les variables de classe sont accessibles par tous les objets de cette classe et ses sous-classes (les objets héritiers, ceux qui sont à un rang inférieur dans la hierarchie). Les variables d’instance sont elles réservées à l’objet instancié et ses données sont propres à cet objet.
Dans ScriptableDocApp que nous avons étudié la dernière fois (vous pouvez télécharger le projet ici), nous avons créé une classe appelée MyDocument qui est une sous-classe de NSDocument. Quand nous avons créé notre fichier ScriptableAppDoc.scriptSuite, nous n’avions qu’à établir une connexion entre l’application et la classe MyDocument, et à indiquer au système de script quel type d’objet nous voulions rendre scriptable.
Ceci nous a permis de créer de nouveaux objets MyDocument qui répondent aux mêmes commandes AppleScript disponibles pour la classe NSDocument fournies dans la NSCoreSuite. S’occuper de scripts dans les applications vous réservera de belles surpirses, car, dès qu’une classe est scriptable, manipuler ses variables d’instance n’est plus qu’un problème de méthodes d’accession.
Accesseurs
L’ Objective-C offre une façon conventionnelle de récupérer et de définir les valeurs des variables d’instance. Ces méthodes sont appelées accesseurs. La convention utilisée est d’appeler la méthode pour accéder à une variable d’instance du nom de la variable d’instance. Donc, si vous avez la variable d’instance suivante :
NSString *myString;
la méthode qui permet de récupérer le contenu de cette variable devrait être:
- (NSString)myString {
return myString;
}
Pour l’utiliser dans votre code Objective-C, vous devriez avoir quelque chose comme cela :
[myobject myString];
où myobject est une instance de votre classe, auquel vous envoyez le message myString qui invoque la méthode myString qui, elle, retourne la valeur de la variable d’instance myString. Incroyable !?! Ce qu’il faut en retenir, c’est que, normalement, on récupère le contenu d’une variable d’instance grâce à un accessuer.
Maintenant, l’autre moitié du boulot, c’est de définir la valeur du variable d’instance. La méthode de définition, par convention, s’appelle set<VariableName> où la première lettre de la variable est en majuscules. Dans notre exemple on aurait :
- (void)setmyString: (NSString *)str {
myString = str;
return;
}
qu’on utiliserait comme suit :
[myobject setmyString:@"hello"];
Ici nous passons une chaîne à notre méthode, qui utilise la variable locale str déclarée au sein de la méthode, et la lions à la variable d’instance.
Vous n’êtes pas obligés de suivre ces convenions, beaucoup de programmeurs choisissent de ne pas le faire, mais si vous le faîtes AppleScript sera automatiquement capable de récupérer et de définir les valeurs de vos variables d’instance. Cette convention de nommage des accesseurs est souvent appelée codage des valeurs-clés (key-value coding), et AppleScript et Cocoa l’utilise régulièrement.
Le codage des valeurs-clés en pratique
Voyons un peu comment tout cela fonctionne. Nous allons ajouter deux variables d’instance à la classe MyDocument du projet ScriptableDocApp que nous avions créé la dernière fois. La NSTextSuite a été incluse dans la séquence de script ScriptableDocApp, mais n’avait pas de fonction puisque nous n’avions pas de classes pour manipuler le texte. Nous allons faire d’une pierre deux coups en connectant nos variables d’instance à un objet NSTextView que nous allons ajouter dans Interface Builder. Nous utiliserons la seconde variable d’instance pour stocker la partie “scriptable” de l’objet NSTextView, qui est un objet de la classe NSTextStorage. Nous ajouterons les méthodes-accesseurs (get et set) pour la variable dinstance de la NSTextStorage, puis enfin ajouterons la relation entre l’objet MyDocument et la NSTextStorage à notre fichier ScriptableDocApp.scriptSuite.
Pour commencer, vous pouvez démarrer un nouveau projet et suivre ce tutoriel ou simplement télécharger le projet complet ici. Je vais commencer avec une nouvelle application basée sur des documents Cocoa dans Project Builder et l’appeler une nouvelle fois ScriptableDocApp. Lorsque vous avez créé le projet, il vous faut permettre le support d’Applescript pour l’application.
Je fais cela en éditant le fichier Info.plistd’un projet, mais d’astucieux lecteurs m’ont envoyer un truc bien utile pour faire cela de façon plus simple. Dans la barre verticale de gauche, où sont affichés les fichiers, il y a un onglet Targets. Cliquez dessus et dans la zone en haut et à gauche vous allez voir le nom de votre projet avec une cible juste à côté. Cliquez dessus et dans la fenêtre à droite cliquez sur l’onglet Applications Settings. Vous avez alors accès à la section Basic Information.
C’est ici que sont réglés la plupart des informations de Info.plist, mais il n’y a rien concernant AppleScript dans l’interface simple. Cliquez sur le bouton “Expert” à droite pour faire apparaître une liste d’ informations. Cliquez sur “New Sibling” et changez le nom du nouvel élément créé en “NSAppleScriptEnabled”. Double-cliquez dans la colonne “value” à droite de la ligne NSAppleScriptEnabled et mettez la valeur à “YES” puis sauvegardez le projet. Cela rend AppleScript accessible dans le projet une fois construit et ce réglage est définitif, indépendament des compilations, et, ce, même si le projet est vidé pour recommencer.

Maintenant, cliquez à nouveau sur l’onglet Files dans la barre de gauche pour revenir là où vous étiez. Ouvrez le dossier “Classes” et cliquez sur le fichier MyDocument.h. Nous allons ajouter deux variables d’instance et deux méthodes de classes accesseurs comme le montre ce qui suit :
#import <Cocoa/Cocoa.h>
@interface MyDocument : NSDocument
{
IBOutlet NSTextView *textView;
NSTextStorage *textStorage;
}
- (NSTextStorage *)textStorage;
- (void)setTextStorage:(id)ts;
@end

Si vous ne comprenez pas tout, allez jeter un oeil sur les articles de Mike Beam sur les bases d’ Objective-C et de Cocoa avant d’aller plus loin.
Clicquez sur le fichier MyDocument.m et faites défiler l’affichage vers le bas au delà des autres méthodes de classe mais avant le marqueur de fin “@end”. Collez le code suivant :
- (NSTextStorage *)textStorage {
NSLog(@"textStorage called");
return textStorage;
}
- (void)setTextStorage:(id)ts {
// ts can actually be a string or an attributed string.
NSLog(@"setTextStorage called");
if ([ts isKindOfClass:[NSAttributedString class]]) {
[[self textStorage] replaceCharactersInRange:
NSMakeRange(0, [[self textStorage] length]) withAttributedString:ts];
} else {
[[self textStorage] replaceCharactersInRange:
NSMakeRange(0, [[self textStorage] length]) withString:ts];
}
}
Dans ces deux méthodes, j’ai laissé un appel à NSLog, qui peut servir à déboguer et voir ce qui se passe durant l’exécution des programmes. Vous pourrez voir la sortie dans Project Builder quand vous construirez et lancerez l’application et cela vous aidera à voir le contenu des valeurs-clés pendant le déroulement du programme.
Maintenant, nous avons créé nos variables d’instance, mais il nous faut ajouter du contenu à l’ensemble. Si vous regardez de près les variables d’instance que nous avons ajoutées, vous remarquez qu’une est déclarée comme IBOutlet de la classe NSTextView. L’autre est un objet NSTextStorage. Nous allons ajouter, l’objet NSTextView dans Interface Builder, tandis que l’objet NSTextStorage va être créé automatiquement pour nous, et nous n’aurons qu’à l’instancier pour l’utiliser.

- Tout d’abord, ouvrez le Dossier des Ressources, sur la gauche del’écran, et double-cliquez sur le fichier MyDocument.nib.Cela lancera Interface Builder et ouvira votre fichier d’interface”.nib”. Ce fichier contient les objets Cocoa qui “habillent” votreclasse MyDocument.
- Si vous regardez dans la fenêtre de MyDocument.nib,vous verrez un cube bleu nommé “Propriétaire du Fichier”(File’s Owner). Cliquez dessus pour le sélectionner etaccéder aux classes en cliquant sur l’onglet “Classes” juste audessus.

- Vous devriez voir apparaître la classe MyDocument.Contrôle-cliquez sur le nom MyDocumentet vous verrez apparaître un menu contextuel. Choisissez d’ajouterune connexion (Add Outlet) à MyDocument.
- Changez le nom de myOutlet en textView et changez le type en NSTextView.
- Dans la palette d’objets Cocoa, choisissez l’icône quiressemble à une fenêtre de texte et tirez une NSTextView dans la fenêtre de votre document.
- Redimensionnez-la à votre goût.
- Revenez à la fenêtre MyDocument.nibet cliquez sur l’onglet “Instances”.
- Maintenant, contrôle-cliquez sur le cube bleu et tirez uneligne jusqu’au NSTextItem de la fenêtrejuste au-dessus.
- Dans la fenêtre des connexions, sélectionnez la textView et cliquez sur “connect”.
- Sauvegardez votre document et quittez Interface Builder.
De retour dans Project Builder, nous devons toutd’abord “régler” notre variable d’instance textStoragepuis il nous faut la rajouter dans dans nos fichiers scriptSuiteet scriptTerminology.
Pour “régler” textStorage,cliquez sur le fichier MyDocument.m et allezà la méthode nommée windowControllerDidLoadNib.Celle-ci est appelée lorsque la fenêtre est chargéepar l’application. Dorénavant, nous savons que notre textView, présentée comme une IBOutlet par Interface Builder, sera disponible etnous pouvons faire appel à son objet NSTextStorage.Nous faisons cela en ajoutant le code suivant après lecommentaire “Ajouter du code” (Add Code) :
textStorage = [textView textStorage];
Le textStorage de droiteest une méthode de classe des objets NSTextViewqui renvoie un objet de la classe NSTextStorage.
En ce qui concerne le fichier scriptSuite nous refaisons sensiblement la même chose que la dernière fois, mais nous allons ajouter un morceau au paragraphe MyDocument dans la partie ToOneRelationships. Il s’agit juste du nom de notre variable d’instance et du type d’objet dont elle est issue. L’extrait de code suivant présente ce qui doit être ajouté, la version complète est présentée juste après :
Extrait concernant textStorage
<key>textStorage</key> <dict> <key>AppleEventCode</key> <string>ctxt</string> <key>ReadOnly</key> <string>NO</string> <key>Type</key> <string>NSTextStorage</string> </dict>
Le code complet de ScripableDocApp.scriptSuite
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>AppleEventCode</key>
<string>ScDA</string>
<key>Classes</key>
<dict>
<key>MyDocument</key>
<dict>
<key>AppleEventCode</key>
<string>docu</string>
<key>Superclass</key>
<string>NSCoreSuite.NSDocument</string>
<key>ToOneRelationships</key>
<dict>
<key>textStorage</key>
<dict>
<key>AppleEventCode</key>
<string>ctxt</string>
<key>ReadOnly</key>
<string>NO</string>
<key>Type</key>
<string>NSTextStorage</string>
</dict>
</dict>
</dict>
<key>NSApplication</key>
<dict>
<key>AppleEventCode</key>
<string>capp</string>
<key>Superclass</key>
<string>NSCoreSuite.NSApplication</string>
<key>ToManyRelationships</key>
<dict>
<key>orderedDocuments</key>
<dict>
<key>AppleEventCode</key>
<string>docu</string>
<key>Type</key>
<string>MyDocument</string>
</dict>
</dict>
</dict>
</dict>
<key>Name</key>
<string>ScriptableDocApp</string>
</dict>
</plist>
Le fichier ScriptableDocApp.scriptTerminology est exactement le même que la dernière fois et doit ressembler à ça :
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> <plist version="0.9"> <dict> <key>Classes</key> <dict> <key>MyDocument</key> <dict> <key>Description</key> <string>A ScriptableDocApp document.</string> <key>Name</key> <string>document</string> <key>PluralName</key> <string>documents</string> </dict> <key>NSApplication</key> <dict> <key>Description</key> <string>ScriptableDocApp's top level scripting object.</string> <key>Name</key> <string>application</string> <key>PluralName</key> <string>applications</string> </dict> </dict> <key>Description</key> <string>ScriptableDocApp specific classes.</string> <key>Name</key> <string>ScriptableDocApp suite</string> </dict> </plist>
Ajoutez ces deux fichiers comme nous l’avons fait lafois précédente, puis construisez et lancez le projet.
AppleScript
Ça marche et maintenant on peut faire des trucs géniaux !
Essayez ça :
set out to "" tell application "ScriptableDocApp" activate set w to make new document at the beginning of documents set w to the first document set the name of w to "first" set y to count of documents set z to get every document set a to exists document 1 set the text of w to "hello" set the font of the text of w to "Times" set out to get the last character of the first word of the text of w end tell return out
Plutôt pas mal, non ?! La Text Suite estdisponible depuis le dictionnaire de script de notre applicationScriptableDocApp, vous pouvez donc tenter d’autres trucs du mêmegenre.
La prochaine fois
Nous en terminerons avec la Core Suite et mettronsen place les bases des suites personnalisées. A bientôt.

textes originaux en anglais sur O’reilly Variables Inside Cocoa Objects par Brad Dominy
Chargement
Commentaires récents