Les Liaisons Cocoa
Les Liaisons Cocoa représentent un ensemble de technologies que vous pouvez utiliser dans vos applications dans le but d’une implémentation totale du paradigme appelé Model-View-Controller, paradigme dans lequel les modèles encapsulent les données de l’application, les vues affichent et permettent l’édition de ces données, et les contrôleurs servent d’intermédiaires entre les deux. Les Liaisons Cocoa (Cocoa Bindings) réduisent les dépendances entre les modèles, les vues et les contrôleurs, supportent plusieurs façons d’afficher vos données et synchronisent automatiquement les vues lorsque les modèles changent. Les Cocoa Bindings fournissent des contrôleurs extensibles, des protocoles à adopter pour les modèles et les vues, et des suppléments aux classes Foundation et Application Kit. Vous pouvez éliminer la plupart de votre code “glue” en utilisant les liaisons disponibles dans Interface Builder pour connecter les contrôleurs aux modèles et aux vues.
Qui devrait lire ce Document ?
Cocoa Bindings est idéal pour les développeurs écrivant de nouvelles applications et qui sont familiers de Cocoa, ainsi que pour les développeurs d’applications existantes qui souhaitent nettoyer ou éliminer leur code “glue”. Dans la plupart des cas, Cocoa Bindings peut être utiliser pour remplacer les mécanismes Cocoa traditionnels tels que cible-action, la délégation et certains protocoles relatifs aux sources de données. Bien qu’un grand soin ait été apporté pour garantir que les deux approches puissent être utilisées côte à côte dans la même application.
Important
Ce document est au stade préliminaire. Bien qu’il ait fait l’objet d’une revue de fiabilité technique, il n’est pas final. Les Cocoa Bindings sont disponibles pour les applications Cocoa tournant sous Mac OS X version 10.3 et ultérieure.
Organisation de ce Document
Les articles suivants couvrent les concepts clés qui permettent de comprendre comment les Cocoa Bindings fonctionnent :
- “Que sont les Cocoa Bindings ?” décrit les avantages offerts par les liaisons Cocoa aux développeurs ; prodigue un rapide survol de leur fonctionnement ; et quel modèle de conception vous devrez adopter pour utiliser cette technologie.
- “Comment fonctionnent les Liaisons Cocoa ?” décrit en détail les technologies supportant les liaisons Cocoa et comment elles interagissent.
- “Modélisation d’Object” couvre les bases en définissant la terminologie utilisée pour décrire les modèles et en introduisant aux concepts cachés derrière le codage clé-valeur.
- “Préférences Utilisateur et Liaisons” décrit le rôle de NSUserDefaultsController et comment il fonctionne avec NSUserDefaults.
Ces articles contiennent des exercices qui vous enseigneront comment utiliser les Cocoa Bindings :
- “Créer une Interface Maître-Détail” explique comment implémenter une interface maître-détail basique dans laquelle une vue de table est utilisée dans l’interface maître pour afficher une suite d’objets, et d’autres vues sont utilisées dans l’interface détail pour afficher l’objet sélectionné de la suite.
- “Afficher des Images en utilisant les Liaisons” décrit les nombreuses options utilisées pour l’affichage d’images en colonnes et contient un exemple de transformateur de valeur personnalisé.
- “Implémenter des Relations un pour un en utilisant des Menus Pop-up” explique comment implémenter des relations un pour un modifiables sous forme de menus pop-up.
- “Filtrer en utilisant un Contrôleur de table personnalisé” explique comment ajouter un champ de recherche à l’interface maître pour filtrer les objets qu’elle affiche.
Voir Aussi
Il y a d’autres technologies, pas complètement couvertes dans cet article, qui sont fondamentales au fonctionnement des liaisons. Vous souhaiterez lire ces sujets si vous voulez acquérir une meilleure compréhension de ce sur quoi sont basés les Cocoa bindings, ou si vous êtes amenés à utiliser ces technologies indépendamment des liaisons. Par exemple, cet article n’explique pas comment utiliser les méthodes définies dans le protocole d’observation basé sur la notion de clé-valeur. Référez vous à ces documents (en anglais) pour de plus amples détails :
- Developing Cocoa Applications Using Bindings: A Tutorial vous guide au travers de la construction de l’application Convertisseur de Monnaies en utilisant les Cocoa Bindings.
- Cocoa Bindings Reference énumère les classes qui supportent les Cocoa Bindings et donne la description des liaisons de chaque classe, avec en plus les options et les placeholders supportés.
- Key-Value Coding couvre tous les aspects du protocole de coding basé sur la notion de clé-valeur qui permet à des objets d’accéder aux propriétés d’autres objets.
- Key-Value Observing couvre les aspects du protocole d’observation basé sur la notion de clé-valeur qui permet à des objets d’observer les changements survenus dans d’autres objets.
- Value Transformers décrit comment utiliser des transformatteurs de valeur pour convertir des valeurs d’un type donné à un autre.
- Sort Descriptors décrit comment utiliser des descripteurs de tri dont le but est de spécifier le mode de tri des collections d’objets.
Voir aussi sur Project:Omega, les articles suivants :
Que sont les Cocoa Bindings ?
Dans leur sens fonctionnel le plus simple, la technologie des Liaisons Cocoa fournit les moyens de maintenir synchronisées les valeurs contenues dans le modèle et la vue sans avoir à écrire des lignes de code “glue”. Elle vous permet d’établir une connexion intermédiaire entre une vue et un morceau de donnée, en établissant une “liaison” de façon à ce qu’un changement survenant chez l’un soit reflété chez l’autre.
Cet article décrit ce que la technologie offre et comment elle simplifie l’écriture d’application. Elle introduit aussi l’idée consistant à dire qu’au lieu de réimplementer complètement une application existante dans le but de lui faire utiliser les liaisons mieux vaut les incorporer par étape.
Cet article décrit aussi à un niveau conceptuel comment fonctionnent les liaisons Cocoa et le modèle de conception que vous devriez adopter. Il vous donne un bref aperçu du modèle de conception Modèle-Vue-Contrôleur, et les bénéfices à en tirer. Puis, il donne un survol conceptuel des principales technologies qui sont à la base des liaisons Cocoa—le codage clé-valeur, l’observation clé-valeur et la liaison clé-valeur—, comment elles fonctionnent et comment elles interagissent. Enfin, l’article explique le rôle des classes contrôleur que les liaisons Cocoa fournissent et les raisons pour lesquelles vous devriez les utiliser.
“Comment fonctionnent les liaisons ?” décrit plus en détail les technologies supportées.
Les Avantages de l’Utilisation des Liaisons
Les liaisons Cocoa offrent le moyen d’améliorer les fonctionnalités et la cohérence de votre application tout en diminuant la somme de code à écrire et à maintenir. Elles prennent en charge pour vous la plupart des aspects de la gestion de l’interface utilisateur en vous permettant de déplacer les tâches effectuées par le code “glue” personnalisé vers les contrôleurs prédéfinis et réutilisables. Elles vous aident à construire des applications fignollées et facile d’usage qui exploitent les relations inter-objets, prodiguent des tables triables et incluent une gestion intelligente de sélection de données.
En temps normal, vous n’avez pas à réécrire complètement votre application si vous souhaitez adopter les liaisons Cocoa. Par exemple, vous pouvez faire en sorte que les Préférences Utilisateur soient gérées par les liaisons Cocoa sans affecter le reste d’une application. Vous trouverez l’utilisation des liaisons Cocoa plus facile si votre application adopte les modèles de conception recommandés.
Le Modèle de Conception Modèle-Vue-Contrôleur
Les applications Cocoa adoptent en général le modèle de conception Modèle-Vue-Contrôleur (MVC). Lorsque vous dévelopez une application Cocoa, vous utilisez en général des objets modèles, vues et contrôleurs, chacun ayant sa propre fonction. Les objets modèles représentent les données et sont en général sauvegardés dans un fichier ou dans un autre support de données permanent. Les objets vues affichent les attributs du modèle. Les objets contrôleurs agissent en tant que médiateur de façon à assurer la cohérence de la vue avec les valeurs correspondantes du modèle et la propagation des mises à jour effectuées par l’utilisateur dans la vue vers le modèle. Une bonne compréhension du modèle de conception MVC est essentielle pour comprendre et tirer profit des liaisons Cocoa. Si vous souhaitez en savoir plus, allez lire “Le Modèle de Conception Modèle-Vue-Contrôleur”.
Si vous adoptez le modèle MVC, la plupart du code de votre application sera plus facile à réutiliser et à étendre—vous pouvez réutiliser les classes modèle et vue dans différentes application. L’implémentation d’un objet contrôleur consiste principalement en ce qui est communément appelé “le code glue”. Le code “glue” gère la synchronisation des valeurs du modèle et de leurs vues, il est propre à chaque application. Il est en général pénible et lourd à écrire, contribue peu à la fonctionnalité générale de l’application, mais il doit être bien écrit pour donner une bonne expérience à l’utilisateur.
Figure 1 Les Contrôleurs fournissent le code “glue”

Les liaisons Cocoa remplacent la plupart du code “glue” avec des contrôleurs réutilisables et apportent une infrastructure qui vous permet de connecter l’interface utilisateur avec les données d’une application.
Cocoa utilise de nombreux de termes courants en informatique. Pour éviter toute incompréhension, ces termes sont définis dans la section “Terminologie” de la section Codage Clé-Valeur avec leur sens particulier dans le contexte des liaisons Cocoa.
Qu’est ce qu’une Liaison ?
Une liaison est un attribut d’un objet donné qui peut être lié à une propriété d’un autre objet de façon à ce qu’un changement intervenant dans l’un est reflété dans l’autre. Par exemple, la valeur d’un champ texte pourrait être liée à l’attribut température d’un objet modèle particulier. De façon plus générale, une liaison pourrait spécifier qu’un objet contrôleur “présente” un objet modèle et une autre liaison que la valeur d’un champ texte soit attachée à la propriété temperature property de l’objet présenté par le contrôleur.
Bien que les exemples suivants abordent des cas simples, les liaisons ne sont pas limitées à l’affichage de valeurs textuelles ou numériques. Parmis tant d’autres, une liaison peut spécifier la couleur d’affichage du texte, qu’une vue soit cachée ou pas, ou quels messages et quels arguments doivent être envoyés quand un bouton est pressé.
Un exemple Simple
Prenez pour exemple une application très simple dans laquelle les valeurs d’un champ texte et d’un curseur sont maintenues synchronisées. Considérez d’abord une implémentation qui n’utilise pas les liaisons. Le champ texte et le curseur sont connectés directement l’un à l’autre en utilisant le mode cible-action, où chacun est la cible de l’autre et l’action est takeFloatValueFrom: comme illustré dans la Figure 2. (Si vous ne comprenez pas ceci, vous devriez lire notre Section Programmation Cocoa).
Figure 2 Une application Cocoa simple

Cet exemple illustre le dynamisme de l’environnement Cocoa—les valeurs de deux objets d’interface utilisateur sont maintenus synchronisés sans aucune ligne de code, même sans compiler. Il sert aussi à illustrer le mode de conception cible-action (pour plus de détails, lire “The Target-Action Paradigm”).
Le défaut majeur dont souffre cet exemple, dans son état actuel, est qu’il n’a a aucune application dans le monde réel. Pour trouver la valeur sur laquelle a été positionné soit le champ texte soit le curseur, et ainsi mettre à jour un attribut du modèle, vous avez besoin de connexions vers le champ texte et le curseur, et vous devez écrire un peu de code. En général, vous utilisez un contrôleur qui est connecté aux deux (en se servant d’oulets) et auquel les deux sont connectés (en se servant du mode cible-action), comme illustré dans la Figure 3.
Figure 3 Exemple du curseur utilisant le mode cible-action

Lorsqu’un utilisateur déplace le curseur, il envoie un message action à sa cible (le contrôleur). Le contrôleur à son tour met à jour la valeur dans le modèle et synchronise l’interface utilisateur (le champ texte et le curseur). Bien que cet exemple ne soit pas particulièrement difficile, la situation devient plus complexe si utilisez des modèles et un affichage plus compliqués, surtout si vous utilisez, par exemple, des vues de table permettant des sélections multiples ou si une valeur doit être affichée dans une fenêtre différente. Et vous aurez à écrire tout le code pour supporter cette fonctionnalité.
Les liaisons Cocoa utilisent des objets contrôleurs préfabriqués (sous-classes de NSController) et des technologies de support pour garder automatiquement les valeurs synchronisées. La conception de l’application pour implémenter l’exemple du curseur utilisant des liaisons est illustrée Figure 4.
Figure 4 Illustration du curseur utilisant des liaisons

Notez que cette implémentation n’utilise pas le mode cible-action. Le curseur n’envoie pas de message action au contrôleur. A la place, lorsque le curseur bouge, il informe directement le contrôleur que la valeur de son contenu a changé et ce qu’elle est devenue. Le contrôleur met à jour le modèle et informe à son tour le champ texte que la valeur à afficher a changé. (Dans ces exemples très simples, le contrôleur n’est pas vraiment nécessaire, il l’est cependant dans la plupart des cas). Les mécanismes utilisés pour relayer l’information sont expliqués plus tard dans cet article et de manière plus détaillée dans “Comment fonctionnent les liaisons ?”, mais il est important de se rendre compte que dans la plupart des cas vous n’aurez aucune ligne de code “glue” à écrire.
Options de Liaisons
De nombreuses liaisons vous permettent de spécifier des options afin de personnaliser leur comportement. Il y a trois types d’options : transformateurs de valeur, formattage de l’affichage (placeholders) et d’autres paramètres.
Un transformateur de valeur, comme son nom l’indique, applique une transformation à une valeur. Un transformateur de valeur peut aussi permettre des transformations inversées. Le framework Foundation fournit la classe abstraite NSValueTransformer et de nombreux transformateurs, y compris un qui rend négatif une valeur—en fait, il transforme un Booléen YES en NO (et vice versa). Vous pouvez aussi implémenter vos propres transformateurs.
Pour se rendre compte de l’utilité des transformateurs, supposez que dans l’exemple précédent le nombre dans le modèle représente des températures en degrés Fahrenheit, mais que vous souhaitiez les afficher en Celsius. Vous pourriez implémenter un transformateur réversible qui convertirait les valeurs d’une échelle à une autre. Puis, si vous le spécifiez en tant qu’option transformateur pour le curseur et le champ texte, comme illustré Figure 5, l’interface utilisateur affichera la température en Celsius, et toute nouvelle valeur provenant du curseur ou du champ texte sera convertie en Fahrenheit.
Figure 5 Affichage de la température en utilisant des transformateurs

Pour en découvrir plus sur les transformateurs, lisez Value Transformers (l’article comprend aussi une implémentation du transformateur Fahrenheit vers Celsius).
Les options de placeholder vous permettent de spécifier ce qu’une vue doit afficher : si la valeur de la propriété à laquelle le formattage est lié est nulle (nil) ; s’il y a des sélections multiples ; ou si pour une quelconque raison la valeur n’est pas applicable.
En plus des transformateurs de valeur et des placeholders, quelques liaisons offrent une variété d’autres options, telles que la mise à jour de la valeur de la liaison en fonction des changements apportés à l’élement d’interface, ou si l’état éditable d’un élément d’interface est automatiquement configuré en fonction de la sélection du contrôleur. Pour une liste complète de toutes les options de laisons disponibles, se reporter à Cocoa Bindings Reference.
Extension du Modèle MVC
L’architecture des liaisons Cocoa est une extension de la configuration traditionnelle du MVC Cocoa, où un unique contrôleur de fabriquation personnelle gère l’interface utilisateur. Elle fournit un ensemble de classes contrôleur réutilisables qui héritent d’une super-classe abstraite, NSController. Dans une application basée sur les liaisons, il peut y avoir plusieurs contrôleurs—le vôtre (comme une sous-classe NSWindowController, gérant l’interface utilisateur d’un document) et d’autres sous forme de sous-classes de NSController et gérant différentes parties de l’interface utilisateur. Vous pouvez aussi créer vos propres sous-classes des classes contrôleur standard de l’Application Kit—en particulier, vous pouvez sous-classer NSArrayController pour personnaliser les comportements de tri et de filtre.
D’autres figures de ce document présentent un raccourci pratique. Bien que l’instance de NSController est conceptuellement liée directement à son objet modèle, dans la plupart des situations la liaison sera “indirecte”, vers une variable de votre objet document, comme illustré Figure 6.
Figure 6 Configuration typique de liaisons utilisant un contrôleur existant

Technologies de Support
Les liaisons Cocoa reposent principalement sur deux autres technologies, le codage clé-valeur (key-value coding, KVC) et l’observation clé-valeur (key-value observing, KVO). Les liaisons elles-mêmes sont établies en utilisant la liaison clé-valeur (key-value binding, KVB) comme illustré Figure 7. En pratique, vous aurez généralement besoin de comprendre ces technologies seulement si vous souhaitez créer vos propres vues personnalisées avec les liaisons. Si vous souhaitez utiliser les liaisons, la seule chose qui vous est imposée est que vos classes modèle doivent être compatibles avec les conventions du codage clé-valeur au niveau de toutes les propriétés que vous souhaitez lier.
Liaison Clé-Valeur
Une liaison est établie avec un message bind: toObject:withKeyPath:options: qui indique au récepteur de garder synchronisé son attribut spécifié—modulo les options—avec la valeur de la propriété identifiée par le chemin d’accès à la clé de l’objet spécifié. Le récepteur doit être attentif aux changements pertinents survenants dans l’objet auquel il est lié et doit réagir à ces changements. Le récepteur doit aussi informer l’objet des changements survenus sur l’attribut lié. Après qu’une liaison ait été établie il y a deux aspects dans le maintien de la synchronisation de la vue et du modèle : répondre aux interactions de l’utilisateur avec la vue, et répondre aux changements de valeurs du modèle.
Figure 7 Liaisons établies en utilisant la liaison clé-valeur

Lors d’une modification initiée dans la vue, une valeur mise à jour dans l’interface utilisateur est passée au contrôleur, qui à son tour pousse la nouvelle valeur vers le modèle. Pour préserver l’abstraction requise pour permettre à ceci de fonctionner avec tout objet contrôleur ou modèle, le système utilise un protocole commun d’accès—le codage clé-valeur.
Lors d’une modification initiée dans le modèle, les modèles notifient les contrôleurs et les contrôleurs notifient les vues des changements survenus sur les valeurs sur lesquelles un intérêt a été déclaré en utilisant un protocole commun—l’observation clé-valeur. Notez qu’une modification dans le modèle peut être déclenchée par une manipulation directe du modèle—par exemple avec un évènement AppleScript—ou en conséquence d’une modification initiée dans la vue—un changement apporté à la température en modifiant le champ Celsius doit être propagé vers le curseur.
Codage Clé-Valeur
Le codage clé-valeur est un mécanisme par lequel vous pouvez accéder à la propriété d’un objet en utilisant le nom de la propriété dans une chaîne de caractères—la “clé”. Vous pouvez aussi utiliser les chemins d’accès aux clés pour suivre les relations entre objets. Par exemple, étant donné une classe Employé avec un attribut firstName, vous pourriez récupérer le prénom d’un employé en utilisant le codage clé-valeur avec la clé firstName. Si Employé a une relation appelée “manager” vers un autre Employé, vous pourriez récupérer le prénom du manager d’un employé en utilisant le codage clé-valeur avec la clé manager.firstName. Pour plus de détails, référez vous à Key-Value Coding.
Rappelez vous qu’une liaison spécifie le chemin d’accès à une propriété à laquelle un attribut donné est lié. Si la valeur du curseur ou du champ texte est modifiée, elle utilise le codage clé-valeur—en utilisant comme clé le chemin d’accès spécifié—pour communiquer ce changement directement au contrôleur, comme illustré Figure 8. Notez que les flèches de la figure représentent la direction prises par les messages et par le flux d’information. La nouvelle valeur est passée à partir de l’élément d’interface vers le contrôleur, et du contrôleur vers le modèle.
Figure 8 Utilisation du codage clé-valeur pour mettre à jour les valeurs

Observation Clé-Valeur
L’observation clé-valeur est un mécanisme par lequel un objet peut se déclarer à un autre de façon à être informé des changements de valeur d’une propriété. Quand un objet ets lié à un autre objet, il s’enregistre lui-même comme observateur de la propriété appropriée de cet objet. Dans notre exemple, le champ texte et le curseur se sont enregistrés comme observateurs de la propriété température du contenu du contrôleur, comme illustré Figure 9.
Figure 9 Observation clé-valeur—enregistrement des observateurs

Notez que les flèches de la Figure 9 indiquent la direction de l’observation, pas celle du flux de données. L’observation est un process “passif” (that the arrows shown in Figure 9 indicate direction of observation, not of data flow. Observation is a “passive” process (semblable à celui effectué lors d’une déclaration dans un NSNotificationCenter en vue de recevoir des notifications). Quand une valeur change, l’objet observé émet un message aux observateurs intéressés pour les notifier, comme illustré Figure 10. Les flèches de la Figure 10 montrent la direction d’émission des messages.
Figure 10 Observation clé-valeur—notification aux observateurs

Quelle est l’utilité des NSControllers ?
En principe, les liaisons peuvent être établies entre presque tous les objets, dès lors qu’ils sont compatibles KVC et KVO. Une vue pourrait être liée directement à objet modèle. Les applications basées sur les liaisons, cependant, utilisent des objets contrôleurs pour gérer des objets modèles individuels et des ensembles d’objets modèles, et pour s’interfacer avec le système des préférences utilisateur.
Il est possible de faire des liaisons directement vers vos objets modèles ou vers vos contrôleurs qui n’héritent pas de NSController—vous perdez cependant (ou devez réimplémenter) les fonctionnalités fournies par les objets contrôleurs de l’Application Kit.
- Les instances de NSController gèrent les valeurs courantes de leur sélection et de leur placeholder. Cela permet à une vue d’afficher une valeur appropriée si la sélection du contrôleur est nulle ou s’il y a une sélection multiple.
- NSController (et les éléments d’interface utilisateur de l’Application Kit qui supportent les liaisons) implémente les protocoles NSEditor et NSEditorRegistration. Le protocole NSEditorRegistration fournit les moyens à un éditeur (une vue) d’informer un contrôleur de changements non confiés. Le protocole NSEditor fournit les moyens de demander au récepteur de confier ou d’annuler tout changement en cours. Bien que les méthodes soient en général appliquées sur des éléments d’interface utilisateur par un contrôleur, elles peuvent aussi être envoyées vers un contrôleur, en réponse par exemple à une tentative d’enregistrement de document ou de fermeture d’une application.
Les Classes NSController
NSController est une classe abstraite. Ses sous-classes concrètes sont NSObjectController, NSUserDefaultsController et NSArrayController. NSObjectController gère un seul objet et fournit les fonctionnalités expliquées plus loin. NSUserDefaultsController fournit une interface commode au système de préférences.
NSArrayController gère un tableau d’objets modèle et maintient une sélection. NSArrayController vous permet aussi d’ajouter et de retirer des objets du tableau, et lorsque la sélection change, les vues associées sont mises à jour de manière appropriée. Les objets qu’un contrôleur de tableau gère n’ont même pas à être dans le tableau—votre conteneur peut implémenter des méthodes adaptées (des méthodes “accesseur indexé”, définies dans le protocole NSKeyValueCoding) pour présenter les valeurs aux contrôleurs comme si elles étaient dans un tableau.
Que pouvez vous lier ?
Vous pouvez établir des liaisons pour la plupart des classes “vue” de l’Application Kit, telles que NSButton et NSTableView. En utilisant un contrôleur de tableau, par exemple, vous pouvez lier le contenu d’un menu pop-up aux objets du tableau. Le reste de cet article présente un exemple modérément complexe. Bien que les détails soient laissés dans le vague intentionnellement, il sert néanmoins à illustrer un certain nombre de points et il fournit des exemples de liaisons plus complexes.
Exemple dans la réalité
Considérez une application ludique dans laquelle l’utilisateur gère un nombre de combattants dont un peut être sélectionné comme attaquant. Un combattant peut transporter trois armes, chacune d’elle pouvant être choisie n’importe quand. Dans l’application, la liste des combattants est montrée dans une vue de table, le titre de la fenêtre montre le nom de l’attaquant et un menu pop-up montre les armes sélectionnées, comme illustré Figure 11.
Technologies de Support
Les liaisons Cocoa reposent principalement sur deux autres technologies, le codage clé-valeur (key-value coding, KVC) et l’observation clé-valeur (key-value observing, KVO). Les liaisons elles-mêmes sont établies en utilisant la liaison clé-valeur (key-value binding, KVB) comme illustré Figure 7.
En pratique, vous aurez généralement besoin de comprendre ces technologies seulement si vous souhaitez créer vos propres vues personnalisées avec les liaisons. Si vous souhaitez utiliser les liaisons, la seule chose qui vous est imposée est que vos classes modèle doivent être compatibles avec les conventions du codage clé-valeur au niveau de toutes les propriétés que vous souhaitez lier.
Liaison Clé-Valeur
Une liaison est établie avec un message bind:toObject:withKeyPath:options: qui indique au récepteur de garder synchronisé son attribut spécifié—modulo les options—avec la valeur de la propriété identifiée par le chemin d’accès à la clé de l’objet spécifié. Le récepteur doit être attentif aux
changements pertinents survenants dans l’objet auquel il est lié et doit réagir à ces changements. Le récepteur doit aussi informer l’objet des changements survenus sur l’attribut lié. Après qu’une liaison ait été établie il y a deux aspects dans le maintien de la synchronisation de la vue et du modèle : répondre
aux interactions de l’utilisateur avec la vue, et répondre aux changements de valeurs du modèle.
Figure 7 Liaisons établies en utilisant la liaison clé-valeur

Lors d’une modification initiée dans la vue, une valeur mise à jour dans l’interface utilisateur est passée au contrôleur, qui à son tour pousse la nouvelle valeur vers le modèle. Pour préserver l’abstraction requise pour permettre à ceci de fonctionner avec tout objet contrôleur ou modèle, le système utilise un protocole commun d’accès—le codage clé-valeur. Lors d’une modification initiée dans le modèle, les modèles notifient les contrôleurs et les contrôleurs notifient les vues des changements survenus sur les valeurs sur lesquelles un intérêt a été déclaré en utilisant un protocole commun—l’observation clé-valeur. Notez qu’une modification dans le modèle peut être déclenchée par une manipulation directe du modèle—par exemple avec un évènement AppleScript—ou en conséquence d’une modification initiée dans la vue—un changement apporté à la température en modifiant le champ Celsius doit être propagé vers le curseur.
Codage Clé-Valeur
Le codage clé-valeur est un mécanisme par lequel vous pouvez accéder à la propriété d’un objet en utilisant le nom de la propriété dans une chaîne de caractères—la “clé”. Vous pouvez aussi utiliser les chemins d’accès aux clés pour suivre les relations entre objets. Par exemple, étant donné une classe Employé avec un attribut firstName, vous pourriez récupérer le prénom d’un employé en utilisant le codage clé-valeur avec la clé firstName. Si Employé a une relation appelée “manager” vers un autre Employé, vous pourriez récupérer le prénom du manager d’un employé en utilisant le codage clé-valeur avec la clé manager.firstName. Pour plus de détails, référez vous à Key-Value Coding. Rappelez vous qu’une liaison spécifie le chemin d’accès à une propriété à laquelle un attribut donné est lié. Si la valeur du curseur ou du champ texte est modifiée, elle utilise le codage clé-valeur—en utilisant comme clé le chemin d’accès spécifié—pour communiquer ce changement directement au contrôleur, comme illustré Figure 8. Notez que les flèches de la figure représentent la direction prises par les messages et par le flux d’information. La nouvelle valeur est passée à partir de l’élément d’interface vers le contrôleur, et du contrôleur vers le modèle.
Figure 8 Utilisation du codage clé-valeur pour mettre à jour les valeurs
Observation Clé-Valeur
L’observation clé-valeur est un mécanisme par lequel un objet peut se déclarer à un autre de façon à être informé des changements de valeur d’une propriété. Quand un objet ets lié à un autre objet, il s’enregistre lui-même comme observateur de la propriété appropriée de cet objet. Dans notre exemple, le champ texte et le curseur se sont enregistrés comme observateurs de la propriété température du contenu du contrôleur, comme illustré Figure 9.
Figure 9 Observation clé-valeur—enregistrement des observateurs

Notez que les flèches de la Figure 9 indiquent la direction de l’observation, pas celle du flux de données. L’observation est un process “passif” (that the arrows shown in Figure 9 indicate direction of observation, not of data flow. Observation is a “passive” process (semblable à celui effectué lors d’une déclaration dans un NSNotificationCenter en vue de recevoir des notifications). Quand une valeur change, l’objet observé émet un message aux observateurs intéressés pour les notifier, comme illustré Figure 10. Les flèches de la Figure 10 montrent la direction d’émission des messages.
Figure 10 Observation clé-valeur—notification aux observateurs
Quelle est l’utilité des NSControllers ?
En principe, les liaisons peuvent être établies entre presque tous les objets, dès lors qu’ils sont compatibles KVC et KVO. Une vue pourrait être liée directement à objet modèle. Les applications basées sur les liaisons, cependant, utilisent des objets contrôleurs pour gérer des objets modèles individuels et des ensembles d’objets modèles, et pour s’interfacer avec le système des préférences utilisateur. Il est possible de faire des liaisons directement vers vos objets modèles ou vers vos contrôleurs qui n’héritent pas de NSController—vous perdez cependant (ou devez réimplémenter) les fonctionnalités fournies par les objets contrôleurs de l’Application Kit.
- Les instances de NSController gèrent les valeurs courantes de leur sélection et de leur placeholder. Cela permet à une vue d’afficher une valeur appropriée si la sélection du contrôleur est nulle ou s’il y a une sélection multiple.
- NSController (et les éléments d’interface utilisateur de l’Application Kit qui supportent les liaisons) implémente les protocoles NSEditor et NSEditorRegistration. Le protocole NSEditorRegistration fournit les moyens à un éditeur (une vue) d’informer un contrôleur de changements non confiés. Le protocole NSEditor fournit les moyens de demander au récepteur de confier ou d’annuler tout changement en cours. Bien que les méthodes soient en général appliquées sur des éléments d’interface utilisateur par un contrôleur, elles peuvent aussi être envoyées vers un contrôleur, en réponse par exemple à une tentative d’enregistrement de document ou de fermeture d’une application.
Les Classes NSController
NSController est une classe abstraite. Ses sous-classes concrètes sont NSObjectController, NSUserDefaultsController et NSArrayController. NSObjectController gère un seul objet et fournit les fonctionnalités expliquées plus loin. NSUserDefaultsController fournit une interface commode au système de préférences. NSArrayController gère un tableau d’objets modèle et maintient une sélection. NSArrayController vous permet aussi d’ajouter et de retirer des objets du tableau, et lorsque la sélection change, les vues associées sont mises à jour de manière appropriée. Les objets qu’un contrôleur de tableau gère n’ont même pas à être dans le tableau—votre conteneur peut implémenter des méthodes adaptées (des méthodes “accesseur indexé”, définies dans le protocole NSKeyValueCoding) pour présenter les valeurs aux contrôleurs comme si elles étaient dans un tableau.
Que pouvez vous lier ?
Vous pouvez établir des liaisons pour la plupart des classes “vue” de l’Application Kit, telles que NSButton et NSTableView. En utilisant un contrôleur de tableau, par exemple, vous pouvez lier le contenu d’un menu pop-up aux objets du tableau. Le reste de cet article présente un exemple modérément complexe. Bien que les détails soient laissés dans le vague intentionnellement, il sert néanmoins à illustrer un certain nombre de points et il fournit des exemples de liaisons plus complexes.
Exemple dans la réalité
Considérez une application ludique dans laquelle l’utilisateur gère un nombre de combattants dont un peut être sélectionné comme attaquant. Un combattant peut transporter trois armes, chacune d’elle pouvant être choisie n’importe quand. Dans l’application, la liste des combattants est montrée dans une vue de table, le titre de la fenêtre montre le nom de l’attaquant et un menu pop-up montre les armes sélectionnées, comme illustré Figure 11.
Figure 11 Interface utilisateur pour l’application Combattants

Les Combattants sont représentés par des instances de la classe Combattant. Dans cette classe, chaque arme est référencée sous forme de variable d’instance séparée, comme illustré Figure 12. Cependant, en implémentant des méthodes d’acces “indexées” appropriées (définies par le protocole KVC), la classe Combattant peut permettre à un contrôleur de tableau d’accéder aux armes comme si elles étaient dans un tableau.
Figure 12 La classe Combattant

Lorsque l’utilisateur choisit un attaquant à partir de la vue de table, le titre de la fenêtre est mis à jour pour refléter le nom de l’attaquant et le titre du menu pop-up est mis à jour pour refléter les armes de l’attaquant sélectionné. Lorsque l’utilisateur active le menu, son contenu est créé dynamiquement à partir des armes portées par le combattant. Quand l’utilisateur sélectionne un élément du menu, l’arme sélectionné du combatant est modifié pour correspondre à cet élément du menu. Si un attaquant différent est sélectionné, le titre du menu pop-up, de la sélection et de la fenêtre est mis à jour. La Figure 13 illustre comment l’interface utilisateur de l’application Combattants peut être implémentée en utilisant les liaisons. La vue de table est liée à un contrôleur de tableau qui gère un tableau de combattants. Le titre de la fenêtre est lié au nom du combattant sélectionné. Le menu pop-up récupère sa liste d’éléments à partir d’un contrôleur de tableau lié à la “table” des armes de l’attaquant, et sa sélection est liée à l’arme sélectionnée de l’attaquant.
Figure 13 L’application Combattants gérée par les liaisons 
Cet exemple illustre un certain nombre de points :
- Vous pouvez utiliser plus d’un objet contrôleur dans une application.
- Différent aspects d’un élément d’interface utilisateur peut être lié à des contrôleurs différents.
- Vous pouvez utiliser vos propres classes modèles.
Enfin, l’accent devrait être mis sur le fait que cet exemple ne requiert aucun code pour mettre l’interface sur pied—les contrôleurs et les liaisons peuvent tous être créés dans Interface Builder. Cela représente une réduction de l’effort de programmation considérable comparé à l’approche traditionnelle basée sur le mode cible-action.
Comment fonctionnent les liaisons ?
Cet article prodigue une explication conceptuelle sur la manière dont fonctionnent les liaisons Cocoa. Il décrit :
- Comment sont établies les connexions entre le modèle et le contrôleur, et entre le contrôleur est la vue, en utilisant la liaison clé-valeur.
- La suppression d’une liaison.
- Les protocoles NSEditor et NSEditorRegistration.
- Les technologies que les liaisons Cocoa utilisent pour supporter la communication entre le modèle, la vue et le contrôleur, à savoir le codage clé-valeur et l’observation clé-valeur.
- Comment ces nombreuses technologies interagissent.
Vous devrez être familier des concepts présentés dans “Que sont les Liaisons Cocoa ?”
Survol des Technologies de Support
Cette section présente un survol des technologies qui font que les liaisons Cocoa fonctionnent et et qu’elles interagissent. Elles sont abordées plus en détail dans les sections suivantes. Les liaisons Cocoa reposent sur d’autres technologies—le codage clé-valeur (key-value coding, KVC) et l’observation clé-valeur (key-value observing, KVO)—pour communiquer les changements entre les objets, et sur la liaison clé-valeur (key-value binding, KVB) pour lier une valeur dans un objet à une propriété d’un autre. Les liaisons Cocoa utilisent aussi deux protocoles—NSEditor et NSEditorRegistration—qui permettent de s’assurer que toutes les modifications en cours sont soit annulées soit soumises avant que les éléments d’interface en disposent. Pour comprendre comment ces technologies fonctionnent ensemble, considérez une application de dessin qui permette à l’utilisateur de dessiner des objets graphiques tels que des cercles et des rectangles à l’écran. Parmi d’autres propriétés, un objet graphique a une ombre qui peut être fonction d’une distance variable à partir du centre du graphique selon un angle donné. Un inspecteur affiche la distance et l’angle de l’objet graphique sélectionné dans deux champs texte et une vue personnalisée—un joystick—comme illustré Figure 1.
Figure 1 Exemple d’une application de dessin

L’implémentation de l’inspecteur est illustrée dans la Figure 2. Les deux champs texte et le joystick sont liés à la selection d’un NSArrayController. Le contrôleur contentArray est lié à une table d’objets graphiques. Un graphique a des variables d’instance pour représenter l’angle de son ombre en radians et la distance à partir du centre.
Figure 2 Liaisons pour l’application graphique donnée en exemple
Les valeurs des champs texte sont liés à l’angle et la distance de l’ombre de l’objet graphique ; le joystick fournit une représentation graphique de l’angle et de la distance. L’angle est exprimée en degrés dans le champ texte et celui utilisé en interne par le joystick est spécifié en radians. Leurs liaisons spécifient un transformateur reversible de valeur qui s’occupe des conversions entre les radians et les degrés. La séquence complète des évènements qui surviennent lorsqu’un utilisateur met à jour une valeur dans le champ texte de l’angle est illustrée Figure 3.
Figure 3 Le cycle complet d’édition

- L’utilisateur entre une nouvelle valeur dans le champ texte Angle. Le champ texte utilise le protocole NSEditorRegistration pour indiquer le début et la fin d’une édition.
- En utilisant KVC, au travers du contrôleur la vue met à jour la variable shadowAngle de l’objet modèle. Les liaisons du champ texte spécifient un transformateur réversible radians-vers-degrés, la valeur est donc convertie en radians.
- Au travers de KVO, le modèle informe le contrôleur qu’une mise à jour a été apportée à sa variable shadowAngle.
- Au travers de KVO, le contrôleur informe le joystick et le champ texte angle qu’une mise à jour a été apportée à sa variable de contenu shadowAngle.
Notez que le champ texte Distance n’a été impliqué dans le cycle d’aucune façon. Les liaisons Cocoa n’imposent rien de plus que ce qui est nécessaire. Les sections suivantes expliquent plus en détail comment les liaisons sont établies et comment les technologies sous-jacentes opèrent.
Les Technologies de Support en Détail
Cette section décrit d’abord les technologies qui supportent les liaisons et montre comment elles tiennent leur rôle. Elle explique aussi quelles étapes vous devez franchir afin de tirer profit de ces technologies.
Etablir les Liaisons avec la Liaison Clé-Valeur
La liaison clé-valeur est utilisée pour établir les liaisons. Le protocole informel NSKeyValueBindingCreation déclare des méthodes dont le but est d’établir et de retirer des liaisons entre objets. En addition, il fournit les moyens à une classe d’informer les liaisons qu’elle expose. Dans la plupart des cas, vous devez utiliser bind:toObject:withKeyPath:options:, et seulement lorsque vous établissez des liaisons programmaticalement. L’utilisation de unbind: est expliquée dans “Unbinding”. Les autres méthodes—la méthode de classe exposeBinding:, la méthode d’instance exposedBindings et valueClassForBinding:—ne sont utiles que dans une palette Interface Builder.
NSEditor / NSEditorRegistration
Ensemble, les protocoles NSEditorRegistration et NSEditor permettent aux vues de notifier un contrôleur qu’une édition est en chemin et d’assurer que toute édition en cours ne sera soumise que lorsque ce sera nécessaire. Le protocole informel NSEditorRegistration est implémenté par les contrôleurs pour fournir une interface à une vue—l’éditeur—pour qu’elle puisse informer le contrôleur qu’elle détient des changements qui n’ont pas été soumis. Lorsqu’une édition est initiée, la vue émet un message objectDidBeginEditing: vers le contrôleur. Lorsque l’édition est terminée (par exemple, l’utilisateur presse la touche Retour), la vue émet un message objectDidEndEditing:. Le contrôleur a la responsabilité de pister les éditeurs qui détiennent des changements qui n’ont pas été soumis et de leur demander de soumettre ou d’annuler les éditions en cours au moment approprié—par exemple, si l’utilisateur ferme la fenêtre ou quitte l’application. La requête prend la forme d’un message commitEditing ou discardEditing, défini par le protocole informel NSEditor. NSController fournit une implémentation de ce protocole, comme le font les éléments d’interface utilisateur de l’Application Kit qui supportent les liaisons.
Codage Clé-Valeur
Le codage clé-valeur (KVC) fournit une approche unique pour accéder aux propriétés d’un objet par leur nom (clé) sans avoir à utiliser des méthodes d’accès personnalisées. Le protocole NSKeyValueCoding spécifie entre autres deux méthodes, valueForKey: et setValue:forKey:, qui donnent accès à la propriété d’un objet par un nom spécifié. En addition, les méthodes setValue:forKeyPath: et valueForKeyPath: donnent accès aux propriétés au travers de relations en utilisant des chemins d’accès sous la forme relation.propriété, par exemple, content.lastName. Une liaison pour une propriété donnée spécifie un objet et un chemin d’accès à la propriété de cet objet. Ces informations étant données, l’objet lié peut utiliser le codage clé-valeur—setValue:forKeyPath: précisément—pour mettre à jour l’objet auquel il est lié sans avoir à coder en dur une méthode d’accès, comme illustré Figure 4.
Figure 4 Codage clé-valeur dans les liaisons Cocoa

Puisque les liaisons Cocoa reposent sur KVC, vos objets modèle et contrôleur doivent être compatible KVC pour que les autres objets puissent établir une liaison avec. Pour supporter KVC, vous devez simplement suivre un ensemble de conventions pour le nommage de vos méthodes d’accès, brièvement résumées ici :
- Pour un attribut ou une relation un-pour-un nommé <key>, implémentez des méthodes nommées
<key>etset<Key>:si l’attribut est en lecture-écriture—la casse est importante. - Pour une relation un-pour-n, implémenter soit une méthode nommée
<key>ou à la foiscountOf<Key>etobjectIn<Key>AtIndex:. La dernière paire de méthodes est utile si l’objet n’est pas stocké dans une table. Il est de votre ressort de récupérer une valeur appropriée pour l’index spécifié—la manière dont il a été déterminé n’est pas importante. Pour une relation un-pour-n transformable, vous devrez aussi implémenter soit<setKey>(si vous aviez implémenté<key>) ouinsertObject: in<Key>AtIndex:etremoveObjectFrom<Key>AtIndex:.
Pour obtenir tous les détails de toutes les méthodes déclarées par le protocole NSKeyValueCoding, se reporter à Key-Value Coding.
Observation Clé-Valeur
KVO est un mécanisme qui permet à un objet de se déclarer intéressé par la réception de notifications qui l’informeront de changements de valeurs survenus dans d’autres objets. Pour se déclarer, un observateur émet un message addObserver:forKeyPath:options:context: à l’objet qu’il souhaite observer, message qui spécifie :
- L’object qui va être l’observateur (self, très souvent).
- Le chemin d’accès à la clé à observer (par exemple, selection.name).
- Quelle information sera envoyée par une notification (par exemple, ancienne valeur et nouvelle valeur).
- Eventuellement, une information contextuelle à renvoyer, par exemple un drapeau pour indiquer quelle liaison est affectée.
Un objet observé communique ses changements directement aux observateurs en leur envoyant un message observeValueForKeyPath:ofObject: change:context: (défini par le protocole informel NSKeyValueObserving)—il n’y a aucun objet indépendant semblable à NSNotificationCenter. La Figure 5 illustre comment le changement d’une valeur modèle (l’angle de l’ombre) est communiquée aux vues par le biais de KVO.
Figure 5 Observation clé-valeur dans les liaisons Cocoa

Le message est envoyé aux observateurs à chaque changement d’une propriété observée, indépendamment de la manière dont a été déclenché le changement. (Notez que le protocole lui-même ne fait aucune supposition sur ce l’observateur fera réellement avec l’information).
Un autre aspect important de KVO est que vous pouvez déclarer que la valeur d’une clé comme étant dépendante de la valeur d’une ou plusieurs autres
clés. Un changement survenant dans la valeur associée à l’une des clés ”maîtres” déclenchent une notification de changement pour la valeur de la clé dépendante. Par exemple, les limites d’un objet graphique pourraient être dépendantes de la distance et de l’angle de l’ombre associée. Si l’une de ces valeurs changent, tout objet observant les limites du graphique doit être informé.
La principale condition pour faire usage de KVO est que vos objets modèles doivent être compatibles KVO. Dans la plupart des cas, cela ne nécessite aucun effort—le système “runtime” ajoute automatiquement le support. Par défaut, toute invocation des méthodes KVC résultent en notifications à destination d’observateurs. Vous pouvez aussi implémenter un support manuel—se reporter à Key-Value Observing pour plus de détails.
Unbinding
En général, la seule raison qui vous pousserait à supprimer une liaison sur un objet proviendrait d’une modification programmatique de l’interface utilisateur. Si vous changez les valeurs des liaisons d’un objet, toute valeur déjà existante devra être effacée.
Si vous implémentez une vue ou un contrôleur personnalisé avec des liaisons propres, vous devrez être sûr que les liaisons seront effacées avant qu’elles ne soient supprimées de la mémoire—en particulier, ils devront supprimer tout objet retenu pour la liaison spécifiée dans la méthode ind:toObject:withKeyPath:options: et devront effacer les déclarations d’observation. Il peut être opportun d’implémenter cette logique dans une méhode unbind: que vous appelerez ensuite au tout début de dealloc.
Plus de Détails sur les Liaisons
Cette section examine les liaisons en plus grands détails. Elle décompose—sous la perspective d’une vue personnalisée, un joystick—ce qui arrive lorsqu’une liaison est établie. Cela permet deux choses : explication du code engagé dans l’établissement d’une liaison et dans la réponse aux changements, et survol conceptuel de la manière de créer vos propres vues liées.
Une liaison spécifie quel aspect d’un objet doit être lié à quelle propriété d’un autre, de façon à ce qu’un changement dans l’un soit reflété dans l’autre. Pour une liaison donnée, un objet enregistre donc l’objet cible de la liaison, le chemin d’accès à la clé associé, et toute autre option qui ont été spécifiée.
Vous pouvez établir des liaisons facilement dans Interface Builder en utilisant le panneau “Bindings” de la fenêtre Info. Dans Interface Builder, la liaison angle pour un joystick qui affiche la distance et l’angle de l’ombre d’un objet graphique ressemblerait à ce qui est illustré Figure 6.
Figure 6 Liaisons pour l’angle d’un joystick dans Interface Builder

L’établissement de cette liaison dans Interface Builder est équivallente à l’envoi par programme de ce message au joystick :
[joystick bind:@"angle" toObject:GraphicController withKeyPath:@"selection.shadowAngle" options:options];
Les arguments ont les significations suivantes :
- @”angle”
- Identifie un attribute dont la valeur peut être liée à la valeur d’une propriété d’un autre objet. Notez que le nom de la liaison ne correspond pas nécessairement au nom d’une variable d’instance réelle.
- GraphicController
- L’object contenant la propriété vers laquelle la liaison est établie.
- @”selection.shadowAngle”
- Le chemin d’accès qui identifie la propriété vers laquelle la liaison est établie.
- options
- Un dictionaire qui spécifie des options telles que des placeholders, ou dans ce cas, un transformateur de valeur.
Les informations définies par les arguments peuvent être stockées dans l’objet lié (dans ce cas le joystick) sous forme de variables d’instance, comme expliqué après.
Cet exemple, et ceux qui suivent, suppose que le joystick est représenté par la classe Joystick avec les variables d’instance telles que définies dans l’interface montrée dans le Listing 1.
Listing 1 Interface de la classe Joystick
@interface Joystick : NSView
{
float angle;
id observedObjectForAngle;
NSString *observedKeyPathForAngle;
NSValueTransformer *angleValueTransformer;
// ...
}
Dans sa méthode bind:toObject:withKeyPath:options:, un objet doit au moins faire ce qui suit :
- Déterminer quelle liaison est établie.
- Enregistrer à quel objet il est lié avec quel chemin d’accès à la clé et quelles options.
- Se déclarer comme observateur du chemin d’accès de la clé de l’objet auquel il est lié de façon à recevoir les notifications de changement.
L’extrait de code du Listing 2 montre un implémentation partielle de la méthode bind:toObject:withKeyPath:options: du JoyStick dans le cas de la liaison angle.
Listing 2 Implémentation partielle de la méthode bind:toObject:withKeyPath:options pour la classe Joystick
static void *AngleBindingIdentifier = (void *)@"JoystickAngle";
- (void)bind:(NSString *)binding toObject:(id)observableObject
withKeyPath:(NSString *)keyPath
options:(NSDictionary *)options
{
// Observe les changements dans observableObject -- notez que l'identifiant
// de la liaison est passé comme contexte, ce qui permet de le récupérer dans
// observeValueForKeyPath:...
// De cette manière vous pouvez facilement déterminer ce qui a besoin
// d'être mis à jour.
if ([binding isEqualToString:@"angle"])
{
[observableObject addObserver:self
forKeyPath:keyPath
options:0
context:AngleBindingIdentifier];
// Enregsitre quel objet et quelle chemin d'accès de clé sont associés
// avec cette liaison
observedObjectForAngle = observableObject;
observedKeyPathForAngle = [keyPath copy];
// Enregsitre le transformateur de valeur s'il y en a un
angleValueTransformer = nil;
NSString *vtName = [options objectForKey:@"NSValueTransformerName"];
if (vtName != nil)
{
angleValueTransformer = [NSValueTransformer valueTransformerForName:vtName];
}
}
// L'implémentation continue...
Cette implémentation partielle n’enregistre pas les options de liaison autres que le transformateur de valeur (bien qu’il se peut simplement que la liaison ne l’autorise pas). Néanmoins, elle illustre les principes de base de l’établissement d’une liaison. Notez en particulier les informations contextuelles passées dans le message addObserver:forKeyPath:options:context: ; elles sont retournées dans la méthode observe:ValueForKeyPath:ofObject:change:context: et peuvent être utilisées pour déterminer quelle liaison est affectée par la mise à jour de la valeur.
Répondre aux Changements
Comme indiqué précédemment, il y a deux aspects dans la gestion des changeents—répondre aux changements, provenant de la vue, qui doivent être propagées vers le modèle, et répondre aux changements, provenant du modèle, qui doivent être reflétés dans la vue. Cette section illustre les deux réponses et montre comment KVC et KVO jouent leur rôle.
Mises à jour initiées dans la Vue
Souvenez-vous que le joystick était lié au contrôleur avec la méthode suivante :
[joystick bind:@"angle" toObject:GraphicController withKeyPath:@"selection.shadowAngle" options:options];
Sous la perspective de mises à jour initiées dans la vue, la méthode peut être interprétées comme suit :
- bind:@”angle”
- Si quoi que ce soit associé à angle change,
- toObject: GraphicController
- indique à l’objet spécifié (GraphicController) que
- withKeyPath:@”selection.shadowAngle”
- la valeur de son selection.shadowAngle (du GraphicController) a changé
- options:options
- en utilisant une de ces options qui puisse être appropriée.
Si la valeur associée à angle change—en général, lorsqu’un utilisateur clique ou déplace la souris dans la vue—le joystick devrait passer la nouvelle valeur au contrôleur en utilisant KVC, comme illustré Figure 4. Le joystick devrait alors répondre aux entrées utilisateur comme suit :
- Déterminer les nouvelles valeurs de l’angle et de la distance,
- Mettre à jour son propre affichage de manière appropriée,
- Communiquer les nouvelles valeurs au contrôleur auquel il est lié.
Le Listing 3 montre une implémentation partielle d’une méthode de mise à jour pour la classe Joystick. L’extrait ne traite que de la liaison angle. Il illustre l’utilisation du codage clé-valeur pour communiquer la nouvelle valeur (transformée par le transformateur de valeur si nécessaire) à l’objet observé.
Listing 3 Méthode de mise à jour pour la classe Joystick
-(void)updateForMouseEvent:(NSEvent *)event
{
float newAngleDegrees;
// calcule newAngleDegrees...
[self setAngle:newAngleDegrees];
if (observedObjectForAngle != nil)
{
NSNumber *newControllerAngle = nil;
if (angleValueTransformer != nil)
{
newControllerAngle =
[angleValueTransformer reverseTransformedValue:[NSNumber numberWithFloat:newAngleDegrees]];
}
else
{
newControllerAngle = [NSNumber numberWithFloat:newAngleDegrees];
}
[observedObjectForAngle setValue: newControllerAngle forKeyPath: observedKeyPathForAngle];
}
// ...
}
Notez que cet exemple omet plusieurs détails importants, tels que l’enregistrement de l’éditeur et la vérification que le transformateur de valeur autorise des transformations inversées.
Mise à jour initiée dans le Modèle
Souvenez-vous une fois de plus que le joystick était lié au contrôleur avec la méthode suivante :
[joystick bind:@"angle" toObject:GraphicController withKeyPath:@"selection.shadowAngle" options:options];
Si l’on considère que les modifications sont initiées à partir du modèle, la méthode peut être interprétée ainsi :
- toObject: GraphicController
- Si dans le GraphicController
- withKeyPath:@”selection.shadowAngle”
- selection.shadowAngle change
- bind:@”angle”
- met à jour tout ce qui est associé à la clé angle exposée
- options:options
- en utilisant les options spécifiées (par exemple, en utilisant un transformateur de valeur).
Le récepteur du message s’était déclaré comme observateur du chemin d’accès à la clé de l’objet spécifié (selection.shadowAngle) dans sa méthode bind:toObject:withKeyPath:options:, comme ceci était illustré dans le Listing 2. Les objets observés notifient leurs observateurs en leur envoyant un message observeValueForKeyPath:ofObject:change:context:. Le Listing 4 montre une implémentation partielle de la manière dont la classe Joystick gère les notifications aux observateurs qui en résultent.
La nécessité fondamentale de la méthode observeValueForKeyPath:ofObject:change:context: consiste à mettre à jour la valeur associée à l’attribut opportun. Cet extrait montre aussi comment la méthode peut capturer les informations relatives au “placeholder” qui peut être utilisé dans la méthode d’affichage pour donner un retour visuel à l’utilisateur, dans ce cas en utilisant une variable d’instance qui indique que, pour une quelconque raison, l’angle est “mauvais”.
Listing 4 Méthode d’observation pour la classe Joystick
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
// Vous avez passé l'identifiant de la liaison comme contexte au moment
// de la déclaration comme observateur -- utilisez cela pour décider ce qui
// doit être mis à jour...
if (context == AngleObservationContext)
{
id newAngle = [observedObjectForAngle valueForKeyPath:observedKeyPathForAngle];
if ((newAngle == NSNoSelectionMarker) ||
(newAngle == NSNotApplicableMarker) ||
(newAngle == NSMultipleValuesMarker))
{
badSelectionForAngle = YES;
}
else
{
badSelectionForAngle = NO;
if (angleValueTransformer != nil)
{
newAngle = [angleValueTransformer transformedValue:newAngle];
}
[self setValue:newAngle forKey:@"angle"];
}
}
// ...
[self setNeedsDisplay:YES];
}
Dans la plupart des contrôles la méthode altère la représentation visuelle en fonction de la selection courante.
Modélisation Objets
Cet article définit les termes et présente des exemples de modélisation d’objet et de codage clé-valeur spécifiques aux liaisons Cocoa. La compréhension de termes, tels que “key paths” (chemin d’accès à une clé), est fondamentale pour utiliser les liaisons Cocoa. Cet article est recommandé si vous êtes débutant en conception orientée objet ou en codage clé-valeur.
Lorsque vous utilisez les liaisons Cocoa, vous avez besoin d’une manière de décrire vos objets modèles qui ne dépende pas des vues et des contrôleurs. Une bonne conception réutilisable n’impose pas de dépendances entre d’une part les objets vues et contrôleurs et d’autre part les propriétés du modèle. Les liaisons Cocoa résolvent ce problème en empruntant les concepts et les termes de la technologie des bases de données—en particulier, le modèle entité-relation.
La modélisation entité-relation est une manière de répresenter les objets généralement utilisée pour décrire la structure de donnée d’une source de donnée selon un mode qui permet à ces structures d’être liées à des objets au sein d’un système orienté objet. Notez que la modélisation entité-relation n’est pas propre à cocoa ; c’est une discipline populaire comprenant un ensemble de règles et de termes qui sont documentés dans les ouvrages traitant des bases de données. C’est une représentation qui facilite le stockage et la récupération d’objets d’une source de données. Une source de données peut être une base de données, un fichier, un service web ou toute autre forme de stockage durable. Parce qu’elle n’est indépendante de toute forme de source de données, elle peut être utilisée pour représenter toute sorte d’objet et sa relation à d’autres objets.
Cocoa utilise une version modifiée des règles qui régissent traditionnellement la modélisation entité-relation référencée dans cet article sous l’appellation modélisation object. La modélisation objet est particulièrement utile pour représenter les modèles appartenants au paradigme Modèle-View-Contrôleur. Cela n’est pas surprenant puisque même dans une simple application Cocoa, les modèles sont généralement persistants—stockés dans une sorte de conteneur de données, même si ce n’est juste qu’un fichier.
Entités
Dans le paradigme MVC, les modèles sont des objets qui sont spécifiques à votre application—ils renferment des données et fournissent des méthodes qui opèrent sur ces données. Les modèles sont habituellement persistants mais, plus important, les modèles ne sont pas dépendants de la manière dont sont affichés les données à l’utilisateur.
Dans le modèle entité-relation, les modèles sont appelés entités, les composants d’une entité sont appelés attributs, et les références à d’autres modèles sont appelées relations. Ensemble, les attributs et les relations sont connus sous le nom de propriétés. Avec ces trois simples composants (entités, attributs et relations), des systèmes arbitrairement complexes peuvent être modélisés.
Par exemple, un modèle objet peut être utilisé pour décrire la base de données clients d’une compagnie, une librairie ou un réseau d’ordinateurs. Une librairie comporte des attributs—tels que le titre d’un livre, un numéro ISBN et une date de copyright—et des relations vers d’autres objets—telles que l’auteur et l’abonné. En théorie, si les parties d’un système peuvent être identifiées, le système peut être formulés sous forme de modèle objet.
la Figure 1 montre un exemple de modèle objet utilisé dans une application de gestion financière personnelle. Dans ce modèle, le Compte modélise un compte bancaire individuel (par exemple, votre compte chèque ou épargne) et la Transaction modélise une transaction passée sur le compte (par exemple, un dépôt ou retrait). Chaque transaction peut aussi être assignée à une catégorie pour permettre le suivi des revenus et des dépenses.
Figure 1 Diagramme de l’objet Compte

Attributs
Les Attributs représentent les structures qui contiennent les données. L’attribut d’un objet est en général une valeur simple, telle qu’une échelle, une chaîne de caractères ou un booléen, mais il peut aussi être une structure C ou l’instance d’une classe primaire (telle que NSString, NSNumber, NSData ou NSDate en Cocoa). Les objets non transformables tels que NSColor sont habituellement aussi considérés comme des attributs.
Par example, dans une application financière, vous pourriez implémenter une vue de table affichant une suite d’objets Transaction et quelques un de ses attributs, comme illustré Figure 2. Chaque ligne de la table correspond à une instance de Transaction, et chaque colonne correspond à une propriété de Transaction.
En Cocoa, un attribut correspond généralement à une variable d’instance ou a une méthode d’accès du modèle. Par exemple, Transaction comporte une date, un bénéficiaire et un montant.
Figure 2 Vue de table des Transactions

Relations
Toutes les propriétés d’un modèle ne sont pas des attributs—certaines propriétés sont des relations vers d’autres objets. Votre application est généralement modélisée par plusieurs classes. Au moment de l’exécution, votre modèle objet est une collection d’objets qui forment un graphe. Ces objets sont généralement les objets permanents que votre utilisateur manipule et sauvegarde dans des conteneurs de données ou des fichiers avant de quitter l’application (comme dans une application de gestion de document). La relation entre ces objets modèle peut être suivie pour accèder au moment de l’exécution aux propriétés des objets liés.
Par exemple, dans l’application financière, il pourrait y avoir un compte chèque et un compte épargne, chacun contenant plusieurs transactions, chaque transaction étant rattachée à une catégorie. La Figure 3 illustre les relations entre un objet Compte (checkingAccount) et ses objets Transaction (PG&E, AT&T et Safeway). Dans l’exemple, chaque transaction à un objet Categorie (soit Utilities ou Groceries). Les relations sont indiquées par les flèches allant d’une entité (la source) vers une autre (la destination).
Figure 3 Graphe de l’objet Compte

Cardinalité et Droits de Propriété des Relations
Chaque relation a une cardinalité ; la cardinalité indique combien d’objets destinataires peuvent (potentiellement) adopter la relation. Basiquement, si l’objet destinataire est un objet unique alors la relation est appelée relation 1-pour-1 . Si l’objet destintaire est une suite d’objets (par exemple, une instance de NSArray), alors la relation est appelée relation 1-pour-n . De cette manière, les suites d’objets forment des blocs que vous pouvez utiliser pour construire vos relations 1-pour-n.
Par exemple, dans l’application financière, la relation entre l’objet Transaction et un objet Catégorie est une relation 1-pour-1—une transaction ne peut appartenir qu’à une seule catégorie, trandis que la relation entre le Compte et ses objets Transaction est une relation 1-pour-n.
Notez aussi que les objets destinataires des relations sont parfois sous propriété exclusive et parfois partagées. Par exemple, l’objet Catégorie n’est pas détenu par l’objet Transaction parce que plusieurs transactions peuvent appartenir à la même catégorie. Mais l’objet Compte a un droit de propriété sur ses objets Transaction et il les supprime lorsqu’il est lui-même supprimé—la même transaction ne peut apparaître dans différents comptes.
Accès aux Propriétés
Pour que les modèles, les vues et les contrôleurs soient indépendants les uns des autres, vous devez spécifier les propriétés indépendamment de l’implémentation du modèle. Ceci est accompli en utilisant des paires clé-valeur.
Clés
Vous spécifiez les propriétés d’un modèle en utilisant une simple clé, qui est souvent une chaîne de caractères. La vue ou le contrôleur correspondant utilise la clé pour rechercher l’attribut valeur associé. La construction “valeur” pour un “attribut” renforce la notion indiquant qu’un attribut en tant que tel ne contient pas nécessairement une donnée—la valeur peut être indirectement obtenue ou déduite.
Le codage clé-valeur est utilisé pour effectuer cette recherche—c’est un mécanisme d’accès aux propriétés d’un objet de manière indirecte et, dans certains contextes, de manière automatique. Le codage clé-valeur fonctionne en utilisant les noms des propriétés d’objet—généralement, ses variables d’instance ou méthodes d’accès—comme clés pour accéder aux valeurs de ces propriétés.
Par exemple, vous pourriez obtenir la balance d’un objet Compte en utilisant une clé openingBalance. Si l’objet Compte comporte soit une variable d’instance soit une méthode appelée openingBalance alors une valeur pour cette clé peut être retournée. De la même manière, vous pourriez obtenir les attributs d’une transaction en utilisant les clés date, payee et amount.
Valeurs
Toutes les valeurs d’un attribut particulier sont du même type. Le type de donnée d’un attribut est spécifié dans la déclaration de sa variable d’instance correspondante ou dans la valeur retournée par sa méthode d’accès. Par exemple, si le type de donnée de la variable d’instance reconcile de l’objet Transaction est une valeur BOOL en Objective-C, alors la valeur retournée pour la clé reconcile est aussi une valeur BOOL.
La valeur d’une relation 1-pour-1 est simplement l’objet destination de cette relation. Par exemple, la valeur de la propriété category d’un objet Transaction est un objet Catégorie. La valeur d’une relation 1-pour-n est l’objet collection qui contient les objets destination de cette relation. Par exemple, la valeur de la propriété transactions d’un objet Compte est un NSArray contenant des objets Transaction.
Chemins d’Accès aux Clés (Key Paths)
Un chemin d’accès à une clé est une chaîne de clés séparés par des points qui spécifie une séquence de propriétés d’objet à suivre. La propriété de la première clé est déterminée par, et chaque clé suivante est évaluée en relation à, la propriété précédente. Les chemins d’accès vous permettent de spécifier des propriétés d’objets d’une façon dépendante de l’implémentation du modèle. En utilisant les chemins d’accès, vous pouvez spécifier le chemin, d’une longueur arbitraire, à parcourir dans un graphe objet avant d’arriver à un attribut spécifique de l’objet en question.
Le mécanisme de codage clé-valeur implémente la recherche d’une valeur en donnant un chemin d’accès similaire aux paires clé-valeur. Par exemple, dans l’application de gestion financière, vous pourriez accéder au titre d’une Catégorie via un objet Transaction en utilisant le chemin d’accès category.title où category est une relation de Transaction et title un attribut de Catégorie. Les chemins d’accès sont utiles si vous souhaitez afficher l’attribut d’une entité destinatrice d’une relation. Par exemple, la vue de table des transaction de la Figure 2 est configurée pour afficher le titre de l’objet Catégorie sélectionné, pas l’objet Catégorie en tant que tel.
Toutes les relations d’une chemin d’accès n’ont pas nécessairement une valeur. Par exemple, la relation category peut être nil si l’utilisateur n’a pas sélectionné de catégorie pour la transaction. Dans ce cas, le mécanisme de codage clé-valeur n’est pas cassé—il ne suit simplement pas le chemin et retourne une valeur appropriée telle que nil.
Préférences Utilisateur et Liaisons
Beaucoup d’applications prodiguent une fenêtre de préférences qui permet à l’utilisateur d’en personnaliser les réglages. NSUserDefaultsController apporte une couche placée au dessus de NSUserDefaults et vous permet de lier les attributs des éléments de l’interface utilisateur aux clés correspondantes des préférences utilisateur d’une application.
Qu’est ce que NSUserDefaultsController ?
NSUserDefaultsController est une classe concrète qui implémente une interface compatible liaisons aux NSUserDefaults. Les propriétés d’une instance de NSUserDefaultsController sont liées aux éléments de l’interface utilisateur pour accéder et modifier les valeurs stockées par l’utilisation de NSUserDefaults.
NSUserDefaultsController est généralement utilisée au moment de l’implémentation de l’interface de la fenêtre des préférences ou lorsque vous liez un élément d’interface utilisateur directement à une valeur par défaut. NSUserDefaults reste l’interface principale de programmation à vos réglages par défaut pour le reste de votre application.
Par défaut, NSUserDefaultsController applique immediatement les modifications à ses propriétés. Elle peut être configurée de façon à ce que ces changements ne soient pas appliqués tant qu’un message applyChanges: n’a pas été reçu, permettant au dialogue relatif aux préférences de supporter un bouton “Appliquer”. NSUserDefaultsController supporte aussi le retour aux précédentes valeurs en utiisant la méthode revert:.
NSUserDefaultsController vous permet aussi de fournir un dictionnaire de valeurs “usine” par défaut, qui peuvent être utilisées pour réinitialiser les valeurs configurables par l’utilisateur de votre application, ceci étant en général effectué en réponse à un clic utilisateur sur un bouton “Revenir aux Réglages d’Origine”.
Le Contrôleur Partagé des Réglages Utilisateur par Défaut
NSUserDefaultsController fournit une instance partagée d’elle-même via la méthode de classe sharedUserDefaultsController. Cette instance partagée utilise l’instance de NSUserDefaults retournée par la méthode standardUserDefaults comme modèle, n’a pas de valeurs initiales et applique immédiatement les modifications effectuées au travers de ses liaisons.
L’attention doit être portée sur le fait que les changements apportés aux réglages du contrôleur partagé des valeurs utilisateur par défaut sont appliqués avant que tout fichier nib contenant des liaisons vers ce contrôleur partagé ne soit chargé. Pour être sûr que ces changements soient effectués avant que tout fichier nib ne soit chargé, ils sont souvent implémentés dans la méthode de classe initialize du délégué de l’application ou dans le contrôleur de la fenêtre des préférences.
Liaison vers le Contrôleur Partagé des Réglages Utilisateur par Défaut
Le NSUserDefaultsController partagé est toujours disponible en tant que contrôleur reliable dans la partie “Bindings” de la fenêtre Info d’Interface Builder. Au moment d’établir une liaison vers un réglage utilisateur par défaut, positionner la Controller Key sur values et le Model Key Path sur la clé correspondant à ce réglage par défaut.
La création de liaisons programmatiquement nécessite que vous récupériez le contrôleur partagé des réglages utilisateur par défaut en utilisant la méthode de classe sharedUserDefaultsController. Vous fournissez alors cet objet en tant que observableController à la méthode bind:toObject:withKeyPath:options:.
L’exemple du Listing 1 établit une liaison entre un NSTextField (theTextField) et la valeur par défaut userName en utilisant le contrôleur partagé des réglages utilisateur par défaut.
Listing 1 Relier la clé userName à un NSTextField programmatiquement
[theTextField bind:@"value"
toObject:[NSUserDefaultsController sharedUserDefaultsController]
withKeyPath:@"values.userName"
options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
forKey:@"NSContinuouslyUpdatesValue"]];
initialValues Versus NSUserDefaults registerDefaults:
Le dictionnaire des valeurs initiales vous permet de fournir un moyen de réinitialiser les préférences utilisateur à leurs valeurs “usine”. En général, ces valeurs représentent un sous-ensemble des préférences que votre application enregistre en utilisant la méthode NSUserDefaults registerDefaults:.
L’appel de la méthode NSUserDefaultsController setInitialValues: ne devrait pas être considéré comme une substitution à l’enregistrement des préférences effectuées en utilisant la méthode NSUserDefault registerDefaults:.
L’exemple du Listing 2 charge les valeurs par défaut à partir d’un fichier, enregistre ces valeurs avec NSUserDefaults, puis enregistre un sous-ensemble des valeurs pour qu’elles soient considérées comme les valeurs initiales du contrôleur partagé des réglages utilisateur par défaut. La méthode setupDefaults devrait être appelée à partir de la méthode de classe initialize du délégué de votre application.
Listing 2 Changement des valeurs initiales de l’instance de sharedUserDefaultsController
+ (void)setupDefaults
{
NSString *userDefaultsValuesPath;
NSDictionary *userDefaultsValuesDict;
NSDictionary *initialValuesDict;
NSArray *resettableUserDefaultsKeys;
// Charge les valeurs par défaut des préférences utilisateur
userDefaultsValuesPath=[[NSBundle mainBundle] pathForResource:@"UserDefaults"
ofType:@"plist"];
userDefaultsValuesDict=[NSDictionary dictionaryWithContentsOfFile:userDefaultsValuesPath];
// Les place dans les préférences standard de l'utilisateur
[[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
// Si votre application supporte la réinitialisation d'un sous-ensemble des préférences
// aux valeurs usine, vous devriez positionner ces valeurs dans
// le contrôleur partagé des réglages utilisateur par défaut
resettableUserDefaultsKeys=[NSArray arrayWithObjects:@"Value1",@"Value2",@"Value3",nil];
initialValuesDict=[userDefaultsValuesDict dictionaryWithValuesForKeys:resettableUserDefaultsKeys];
// Positionne les valeurs initiales dans le contrôleur partagé des réglages utilisateur par défaut
[[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:initialValuesDict];
}
Ordre de Recherche des Valeurs par Défaut
Lorsqu’une méthode qui est compatible codage clé-valeur tente de récupérer une valeur pour une clé dans le NSUserDefaultsController, le mode de recherche suivant est utilisé :
- La valeur de la clé correspondante dans
values - La valeur de la clé correspondante dans l’instance de NSUserDefaults retournée par la méthode NSUserDefaultsController
defaults. - La valeur de la clé correspondante dans le dictionnaire des valeurs initiales.
Si aucune valeur n’est trouvée, nil est retournée.
Le chemin de recherche est quelque peu différent lorsque vous récupérez le résultat directement à partoir de l’instance de NSUserDefaults associée au NSUserDefaultsController. Dans ce cas, toute valeur non applicable de NSUserDefaultsController, ainsi que les valeurs du dictionnaire des valeurs initiales, sont ignorées.
Accéder aux Valeurs NSUserDefaultsController Programmatiquement
Bien que NSUserDefaults devrait rester votre interface primaire vers les préférences utilisateur, vous serez amené dans certaines circonstances à récupérer et positionner directement les valeurs des préférences contenues dans une instance de NSUserDefaultsController. Par exemple, au moment d’implémenter des parties de votre fenêtre de préférences qui n’interagissent pas directement avec une liaison, comme changer une police ou choisir un répertoire.
La méthode NSUserDefaultsController values retourne un objet compatible KVC qui est utilisé pour accéder à ces préférences. Pour obtenir la valeur d’une préférence, utilisez la méthode valueForKey:.
[[theDefaultsController values] valueForKey:@"userName"];
De la même manière, pour positionner la valeur d’une préférence, utilisez setValue:forKey:.
[[theDefaultsController values] setValue:newUserName forKey:@"userName"];
Le NSUserDefaultsController prodigue automatiquement une notification de changement de valeur à toute liaison établie pour ce chemin d’accès à la clé.
Créer une Interface Maître-Détail
Cet article explique comment utiliser les liaisons pour implémenter une interface basique maître-détail. Dans la partie interface maître, une vue de table est utilisée pour afficher votre collection d’objets. Dans la partie détail, d’autres vues sont utilisées pour afficher l’objet sélectionné. Cet article contient des exemples de liaison de colonnes de tables à des contrôleurs de table.
Une interface maître-détail peut être déclinée selon de nombreux modes qui ne sont pas complètemet abordés dans cet article. En particulier, il y a beaucoup de cas de vues de table qui fonctionnent parfaitement avec les liaisons Cocoa. Référez vous à ces articles pour des tâches spécifiques :
- “Afficher des Images en utilisant les Liaisons” décrit les nombreuses options utilisées pour l’affichage d’images en colonnes et contient un exemple de transformateur de valeur personnalisé.
- “Implémenter des Relations un pour un en utilisant des Menus Pop-up” explique comment implémenter des relations un pour un modifiables sous forme de menus pop-up.
- “Filtrer en utilisant un Contrôleur de table personnalisé” explique comment ajouter un champ de recherche à l’interface maître pour filtrer les objets qu’elle affiche.
Qu’est ce qu’une Interface Maître-Détail ?
Dans une interface maître-détail, l’utilisateur peut sélectionner des objets à partir d’une liste et visualiser l’objet sélectionné. L’interface maître affiche la collection d’objets et l’interface détail implémente un inspecteur de l’objet sélectionné. Si l’utilisateur change la sélection dans l’interface maître, l’interface est mise à jour pour montrer la nouvelle sélection. Si aucun objet n’est sélectionné, l’interface détail n’affiche rien ou se désactive elle-même (si elle est éditable). Si plusieurs objets sont sélectionnés (en supposant que des sélections multiples sont autorisées), soit l’interface détail est désactivée, soit elle s’applique à tous les objets sélectionnés. En général, une telle interface permet aussi d’ajouter ou de supprimer des objets dans la collection.
Les composants que vous utilisez pour implémenter une interface maître-détail dépendent de votre application. Souvent, l’interface maître est implémentée par une vue de table et l’interface détail est une collection de vues placées au dessus ou en dessous de l’interface maître. La Figure 1 montre l’interface maître-détail d’une application de gestion de médias. Dans cet exemple, la vue de table affiche une collection d’objets média et les vues en dessous affichent les propriétés de l’objet média sélectionné.
Figure 1 Une interface Maître-Détail

Création des Modèles
Cet article suppose que vous avez déjà conçu vos classes modèles, les objets qui contiennent les données de votre application et qui fournissent les méthodes pour opérer sur ces données. Une interface maître-détail est utilisée pour afficher une collection d’objets modèle. De plus, votre objet modèle racine est supposé être une collection de ces objets.
Par exemple, la Figure 2 illustre le diagramme objet des modèles dans une application de gestion de médias. Dans cet exemple, supposez que l’application utilise une architecture basée sur des documents dans laquelle MyDocument (le “File’s Owner” du fichier MyDocument.nib) détient une variable d’instance mediaAssets qui est initialisée avec un tableau d’objets Média.
Figure 2 Un modèle objet

Création des Vues
L’interface maître montrée dans la Figure 1 utilise une vue de table dans laquelle chaque colonne de la table correspond à une propriété des objets affichés. Notez que la vue de table affiche des attributs tels que le titre et la date, tout comme des reltaions telles que l’auteur. La prorpiété auteur est une relation 1-pour-1 (voir Figure 2) dans laquelle l’objet destination est une Personne. Vous pouvez afficher des relations 1-pour-1 de plusieurs manières. Par exemple, l’interface maître n’affiche que le nom de l’auteur. L’interface détail vous permet de sélectionner l’auteur à partir d’un menu pop-up.
Avec Interface Builder, construisez votre interface de façon identique à la Figure 1. Dans cet exemple, une cellule image a été glissée dans la colonne Image pour afficher une version diminuée de l’image du média et un formatteur de date a été glissé dans la colonne Date. La colonne Auteur affiche le nom des auteurs mais pourrait aussi être configurée pour afficher un menu en glissant une cellule menu pop-up, NSPopUpButtonCell, dans la colonne Auteur.
Création des Contrôleurs
Ensuite, vous devez connecter vos vues à vos modèles via un contrôleur. NSArrayController est spécialement conçu pour gérer des collections d’objets pouvant être sélectionnés. Pour cette raison, elle est idéale pour implémenter une interface maître-détail. Après avoir créé un contrôleur de tableau, vous spécifiez que son contenu sera votre collection d’objets modèle. Si le contrôleur de tableau peut être édité, il peut aussi créer des instances des modèles et les ajouter à votre collection. Pour que cela fonctionne, vous devez aussi indiquer au contrôleur de tableau le nom de la classe que l’entité gère.
Suivez ces étapes pour créer et configurer un contrôleur de tableau pour une interface maître-détail :
- Créez un contrôleur de tableau en glissant un NSArrayController à partir de la palette Contrôleurs d’Interface Builder vers votre fichier nib et changez éventuellement le nom du contrôleur. Par exemple, changez le nom en MediaAssetsController.
- Entrez le nom de classe de votre modèle dans le champ “Object Class Name” sur le panneau “Attributes” de la fenêtre “Info” comme montré Figure 3. Dans notre exemple, vous devriez saisir “Media” comme nom de classe.
- Décochez “Editable” sur le panneau “Attributes” si vous ne souhaitez pas que l’utilisateur modifie les modèles, en ajoute ou en supprime dans la collection.
Figure 3 Le panneau Attributs d’un contrôleur de tableau

Relier les Contrôleurs aux Modèles
Chaque classe vue et contrôleur expose un ensemble de liaisons. Vous poouvez inspecter les liaisons d’un objet avec Interface Builder en le sélectionnant et en affichant le panneau “Bindings” de la fenêtre “Info”. Sélectionnez votre contrôleur de tableau dans le fichier nib et affichez ses liaisons comme montré Figure 4.
Vous spécifiez le contenu d’un contrôleur de tableau en configurant sa liaison contentArray. Par exemple, en supposant que le “File’s Owner” maintient une collection d’objets Média appelée mediaAssets, vous configureriez la liaison contentArray comme suit :
- Positionnez l’aspect Bind to sur l’objet qui contient la collection d’objets modèle (par exemple, le “File’s Owner”).
- Laissez à blanc la Controller Key.
- Positionnez le Model Key Path sur le nom du tableau (par exemple, mediaAssets).
la Figure 4 montre ce à quoi devrait ressembler le panneau “Bindings” lorsque la liaison contentArray est révélée.
Figure 4 Le panneau Bindings d’un contrôleur de tableau

Maintenant, ce contrôleur est configuré pour gérer une collection d’objets Média ainsi que pour ajouter et retirer des objets Média du tableau. Retournez au panneau Attributes si vous souhaitez changer le comportement de ce contrôleur—décochez Editable si vous ne voulez pas que l’utilisateur puisse éditer la collection.
Lier les Vues aux Contrôleurs
Ensuite, connectez vos vues à votre contrôleur de tableau en configurant les liaisons de vos objets vues—relier chaque vue des interfaces maître et détail au contrôleur de tableau.
Le réglage de certains paramètres peut être complexe si, par exemple, vous voulez représenter une relation 1-pour-1 éditable. Cet article couvre les types de liaisons de valeur les plus communes. Reportez-vous à “Afficher des Images en utilisant les Liaisons” et “Implémenter des Relations un pour un en utilisant des Menus Pop-up” pour des exemples de liaisons plus complexes.
En général, il est utile de se rappeler que la plupart des vues qui affichent du contenu comportent une liaison appelée value ou une liaison qui contient le terme “value”.
Aussi, compte tenu que vous reliez une vue à un contrôleur, vous devez être familier des propriétés des contrôleurs. Voici les principales propriétés d’un contrôleur de tableau que vous utiliserez généralement comme valeur de la Controller Key :
- arrangedObjects—spécifie la collection d’objets affichés.
- selection—spécifie l’objet sélectionné dans arrangedObjects.
- selectedObjects—spécifie les objets sélectionnés de arrangedObjects dans le cas d’une sélection multiple.
Relier l’Interface Maître
Dans l’interface maître, vous configurez réellement les liaisons des colonnes de la table, pas les liaisons d’une vue de table. Même si vous utilisez un type spécial de cellule dans la colonne de la table, par exemple, une cellule image ou une NSPopUpButtonCell, vous configurez la colonne, pas la cellule. Les liaisons d’une NSTableColumn peuvent changer en fonction de sa cellule.
Dans cet exemple, chaque ligne de la table doit correspondre à un seul objet Média et chaque colonne doit afficher une propriété de cet objet Média. Pour afficher les propriétés, vous sélectionnez d’abord la vue de table, affichez le panneau Bindings et faites apparaître la liaison value. Vous allez alors relier la colonne de la table à la clé arrangedObjects du contrôleur car vous êtes en train de spécifier le contenu de la colonne tout entière, pas une seule cellule. Configurez chaque liaison value pour afficher une propriété de l’objet Média comme suit :
- Positionnez la notion Bind to vers votre objet contrôleur de tableau. Par exemple, MediaAssetsController.
- Positionnez Controller Key sur arrangedObjects (la collection d’objets affichés).
- Positionnez Model Key Path sur la propriété que vous voulez voir apparaître dans cette colonne. Par exemple, dans l’application de gestion de média, positionnez Model Key Path sur date dans la colonne Date.
La Figure 5 illustre ce à quoi devrait ressembler le panneau Bindings lorsque la liaison value de la colonne Title est révélée.
Figure 5 Panneau Bindings pour NSTableColumn

Dans le cas de la propriété “author”, vous pouvez positionner le Model Key Path sur author.lastname si vous souhaitez afficher simplement le nom de famille. Cependant, par défaut, les cellules de colonne sont éditables, donc au moment de lancer l’applicatiion, l’utilisateur pourra changer le nom de famille de l’auteur en éditant le texte de la colonne Author. Si vous ne souhaitez pas cela, sélectionnez la colonne et décochez Editable dans le panneau Attributes de la fenêtre Info.
Notez que certaines vues Cocoa affichent déjà des listes d’objets qui fonctionnent très bien avec la liaison clé-valeur. La Controller Key et le Model Key Path d’une liaison sont concaténés pour récupérer la valeur d’un objet lié. Dans le cas d’une colonne de table, la Controller Key identifie un tableau ; la valeur retournée est donc un tableau. Par exemple, la colonne “Author” utilise la clé arrangedObjects.author.lastname pour obtenir un tableau des noms de famille, instances de NSString, à partir de l’objet lié.
Relier l’Interface Détail
Vous reliez les vues de l’interface détail de manière similaire à celle utilisée pour relier l’interface maître à part le fait que vous positionnez la Controller Key pour chaque liaison sur selection, l’objet en cours de sélection.
Par exemple, vous configurez la liaison value du champ texte “Title” de l’interface détail illustré dans la Figure 1 ainsi :
- Positionnez Bind to sur votre objet contrôleur de tableau. Par exemple, MediaAssetsController.
- Positionnez Controller Key sur selection (l’objet en cours de sélection).
- Positionnez Model Key Path sur la propriété que vous souhaitez afficher dans cette vue. Par exemple, title.
Afficher des Images en Utilisant les Liaisons
En général, vous affichez une image en utilisant soit une NSImageCell ou une NSImageView. Vous pouvez aussi afficher des images dans les colonnes d’une table d’une interface maître ou une vue d’image dans une interface détail. Ces deux composants ont des liaisons similaires et sont donc tous les deux abordés dans cet article. Au moment d’utiliser ces composants, vous devrez aussi prendre des décisions similaires sur la façon dont vous souhaiterez stocker et accéder vos images. Les liaisons “value” de ces composants supportent beaucoup de formats. Vous pouvez spécifier la liaison value en utilisant une NSImage, un chemin d’accès à un fichier ou une URL.
L’exemple présenté dans cet article est une extension de celui présenté dans “Créer une Interface Maître-Détail”. Cet article explique plus spécifiquement comment ajouter une NSImageCell à une colonne de table dans une interface maître (voir Figure 1) et une NSImageView dans une interface détail. Cet article contient aussi un exemple de transformateur personnalisé de valeur qui convertit les noms des fichiers images en chemin d’accès absolus.
Se reporter à “Créer une Interface Maître-Détail” pour les étapes de création de l’interface maître-détail.
Figure 1 Utilisation d’une NSImageCell dans une NSTableColumn

Création des Modèles
La manière de définir les propriétés image au sein de vos modèles dépend de votre application—cela dépend de la manière dont vous souhaitez accéder et stocker les images. Si les images sont stockées sur un disque ou dans votre dossier projet sur le même ordinateur alors vous pouvez les accéder via leur chemin d’accès. Si les images ne sont pas stockées sur un disque mais sur un serveur distant, vous pouvez alors les accéder via une URL. Si les images sont stockées dans une quelconque source de données, vous devrez alors charger les images directement en mémoire. Si vous les chargez, vous devrez définir les propriétés de vos images comme pour de simples objets NSImage. Heureusement, les liaisons Cocoa supportent toutes ces options.
Dans cet exemple, le modèle utilise une NSImage pour représenter la propriété image d’une objet Media comme illustré dans la Figure 2 de “Créer une Interface Maître-Détail”.
Dans le cas d’un chemin d’accès ou d’une URL, vous ne stockez généralement que le nom du fichier dans le modèle au lieu du chemin d’accès absolu ou de l’URL (par exemple, vous ne souhaiterez pas mettre à jour votre modèle à chaque fois que vous déplacerez le dosser des images). Cependant, les liaisons reposent sur un chemin d’accès ou une URL absolu. Une solution consiste à implémenter un transformateur personnalisé de valeur qui prend un nom de fichier en entrée et retourne un chemin d’accès ou une URL en fonction de certaines variables que vous définissez. Se reporter à “Utilisation d’un Transformateur Personnalisé de Valeur pour Convertir les Chemins d’Accès” pour modifier cet exemple de façon à utiliser des chemins d’accès au lieu d’objets NSImage.
Création des Vues
Ensuite, vous créez les vues image soit en déposant une NSImageView sur une fenêtre, soit en déposant une NSImageCell dans la colonne qui affichera les images.
Création des Contrôleurs
Cet exemple suppose que vous avez déjà créé l’interface maître-détail. Suivez les étapes de “Création des Contrôleurs” dans “Créer une Interface Maître-Détail” si vous devez créer un contrôleur de tableau.
Liaison des Values aux Contrôleurs
Ensuite, vous reliez les vues images aux contrôleurs. Quelques liaisons de valeur à choisir pour une NSImageView et une NSTableColumn (contenant une NSImageCell) sont :
- value—un objet NSImage.
- valuePath—un chemin absolu vers un fichier image.
- valueURL—une URL qui retourne un fichier image.
Par exemple, vous configurez la liaison value de la colonne de table image de la Figure 1 comme suit :
- Positionnez Bind to sur votre objet contrôleur de tableau. Par exemple, MediaAssetsController.
- Positionnez Controller Key sur arrangedObjects (la collection d’objets en cours d’affichage).
- Positionnez Model Key Path sur la propriété de NSImage que vous souhaitez afficher dans cette colonne. Par exemple, dans l’application de gestion de média, positionnez le key path sur image.
Vous configurez la liaison value de la NSImageView de l’interface détail de manière similaire, sauf que vous devrez positionner la Controller Key sur selection (en fait, l’objet en cours de sélection).
Se reporter à “Utilisation d’un Transformateur Personnalisé de Valeur pour Convertir les Chemins d’Accès” pour une autre version de cet exemple utilisant la liaison valuePath.
Utilisation d’un Transformateur Personnalisé de Valeur pour Convertir les Chemins d’Accès
Si vous voulez accéder vos images en utilisant un chemin d’accès, vous devez alors relier vos vues à vos contrôleurs en utilisant plutôt la liaison valuePath. Cependant, valuePath doit être un chemin d’accès absolu. En général, vous ne stockez pas les chemins d’accès absolus dans votre modèle mais juste les noms de fichier ou les chemins d’accès relatifs. Vous pouvez convertir un nom de fichier ou un chemin d’accès relatif en chemin d’accès absolu en utilisant une transformateur personnalisé de valeur comme suit.
Création du Transformateur Personnalisé de Valeur
D’abord, créez un transformateur personnalisé de valeur qui prend en entrée un nom de fichier ou un chemin d’accès relatif et qui le convertit en chemin d’accès absolu. Vous faites cela en sous-classant NSValueTransformer et en surpassant les méthodes de classe transformedValueClass et allowsReverseTransformation, comme illustré dans le Listing 1.
Vous implémentez la méthode transformedValue: pour qu’elle effectue la transformation. Par exemple, l’implémentation de la méthode transformedValue: du Listing 1 suppose que les images sont localisées dans le dossier Resources du projet et utilise la méthode resourcePath: de NSBundle pour convertir le nom de fichier en un chemin d’accès absolu. Notez que vous devez modifier cet exemple si vous stockez vos images ailleurs sur le système de fichiers.
Listing 1 Implémentation de PathTransformer
#import "PathTransformer.h"
@implementation PathTransformer
+ (Class)transformedValueClass
{
return [NSString self];
}
+ (BOOL)allowsReverseTransformation
{
return NO;
}
- (id)transformedValue:(id)beforeObject
{
if (beforeObject == nil) return nil;
id resourcePath = [[NSBundle mainBundle] resourcePath];
return [resourcePath stringByAppendingPathComponent:beforeObject];
}
@end
Déclaration du Transformateur de Valeur
Pour pouvoir utiliser le transformateur, vous devez d’abord le déclarer avec NSValueTransformer. Notez que vous déclarez des instances d’un transformateur de valeur et non une sous-classe. En règle générale, vous déclarez des transformateurs de valeur dans une méthode initialize ou dans la méthode applicationDidFinishLaunching: du delegate de l’application. Lorsque vous déclarez un transformateur de valeur, vous lui donnez un nom logique que vous pouvez ensuite utiliser au moment de configurer les liaisons. Par exemple, ajoutez le morceau de code à applicationDidFinishLaunching: pour déclarer une instance appelée PathTransformer :
id transformer = [[[PathTransformer alloc] init] autorelease]; [NSValueTransformer setValueTransformer:transformer forName:@"PathTransformer"];
Relier les Vues aux Contrôleurs en Utilisant les Transformateurs
Enfin, vous spécifiez le transformateur de valeur au moment de relier vos vues à vos contrôleurs en utilisant la liaison valuePath. Par exemple, vous configurez la liaison valuePath de la colonne Image ainsi :
- Positionnez Bind to sur votre objet contrôleur de tableau. Par exemple, MediaAssetsController.
- Positionnez Controller Key sur arrangedObjects (la collection d’objets en cours d’affichage).
- Positionnez Model Key Path sur la propriété contenant le nom du fichier image. Par exemple, dans l’application de gestion de média, positionnez le key path sur imagePath.
- Saisissez le nom logique du transformateur, PathTransformer, dans le champ texte Value Transformer.
La Figure 2 montre le panneau Bindings d’une NSTableColumn dans Interface Builder avec la liaison valuePath révélée et configurée de façon à utiliser un transformateur personnalisé de valeur.
Figure 2 Panneau Bindings d’un NSTableColumn

Pour utiliser la liaison valueURL, implémentez un transformateur de valeur similaire qui convertira des noms de fichiers ou des chemins d’accès relatifs en un objet NSURL approprié. En plus, vous pouvez améliorer la classe PathTransformer pour qu’elle gère d’autres types de transformations de noms de fichiers. Par la suite, déclarez différentes instances avec des noms différents (par exemple, PathTransformer et URLTransformer) pour gérer chaque type de transformation.
Implémenter des Relations 1-pour-1 en Utilisant des Menus Pop-Up
Vous pouvez implémenter une relation 1-pour-1 modifiable en utilisant une NSPopUpButtonCell ou un NSPopUpButton. En fait, cela revient à permettre à l’utilisateur de sélectionner un article de menu à partir d’un menu pop-up de façon à changer l’objet de destination d’une relation 1-pour-1 de votre modèle.
Cet article s’appuie sur l’exemple présenté dans “Créer une Interface Maître-Détail” en y ajoutant un menu pop-up à la vue de table de l’interface maître. Au lieu d’afficher le nom de l’auteur dans la colonne Author, vous allez permettre aux utilisateurs de sélectionner un auteur à partir d’une menu pop-up, comme illustré Figure 1. Notez que si vous n’affichez que le nom de famille, vous n’avez fait qu’aplanir la relation 1-pour-1. En conséquence, si l’utilisateur saisit du texte dans une cellule Author modifiable, il change la valeur de la propriété nom de famille appartenant à l’objet Personne, pas la destination de la relation 1-pour-1 appartenant à l’objet Média. L’utilisation de menus pop-up est une façon d’implémenter une relation 1-pour-1 modifiable.
Se reporter à “Créer une Interface Maître-Détail” pour les étapes de création de l’interface maître-détail.
Figure 1 Utilisation de menus pop-up pour représenter des relations 1-pour-1

Création des Modèles et des Contrôleurs
Pour faire cela, vous avez d’abord besoin des objets modèle et contrôleur de support. En supposant que vous avez déjà à disposition une interface maître, vous créez un tableau de modèles qui seront affichés dans le menu pop-up et vous créez un contrôleur de tableau pour le gérer.
La manière d’initialiser la collection d’objets à afficher dans le pop-up dépend de votre application. Cet exemple suppose que la collection existe déjà et qu’elle est une propriété de File’s Owner (Par exemple, une propriété appelée authors contenant des objets Person).
Créez un NSArrayController en le glissant à partir de la palette Cocoa-Controllers vers votre fichier nib et renommez le de manière appropriée (par exemple, AuthorsController). Il est fréquent d’avoir plusieurs objets contrôleur par fichier nib, le fait de les renommer aide à les identifier. Maintenant, relier le modèle au contrôleur comme suit. Sélectionnez le contrôleur de tableau, afficher le panneau Bindings de la fenêtre Info, faites apparaître la liaison contentArray, et configurez la ainsi :
- Positionnez Bind to sur l’objet qui conserve la collection d’objets modèle (par exemple, le File’s Owner).
- Laissez Controller Key à blanc.
- Positionnez Model Key Path sur le nom du tableau (par exemple, authors).
Saisissez aussi le nom de classe approprié dans le champ Object Class Name sur le panneau Attributes (par exemple, saisissez le nom de classe Person).
Création des Vues
Ensuite, vous créez les vues pop-up en glissant un NSPopUpButton sur une fenêtre ou un NSPopUpButtonCell sur la colonne qui affichera la relation 1-pour-1.
Relier les Vues aux Contrôleurs
Les liaisons primaires d’un NSPopUpMenu et d’une NSTableColumn (contenant une NSPopUpButtonCell) que vous allez utiliser pour mettre en place une relation 1-pour-1 modifiable sont :
- content—la collection d’objets à afficher dans le menu pop-up.
- contentValues—la propriété des objets placés dans content que vous voulez afficher dans le menu pop-up.
- selectedObject—la relation 1-pour-1 que les utilisateurs changeront lorsqu’ils sélectionneront un article du menu pop-up.
Remarque : Quand vous utilisez une NSPopUpButtonCell, vous devez configurer les liaisons de la colonne pas celles de la cellule. Lorsque vous glisser-déposez une NSPopUpButtonCell sur une colonne, la catégorie Value du panneau Bindings de la NSTableColumn change en une catégorie Value Selection contenant les mêmes liaisons qu’un NSPopUpButton.
Par exemple, si vous souhaitez afficher un menu pop-up dans une colonne, configurez la liaison content pour spécifier le contenu du menu pop-up comme suit :
- Positionnez Bind to sur AuthorsController.
- Positionnez Controller Key sur arrangedObjects .
- Laissez Model Key Path à blanc.
Puis configurez la liaison contentValues pour spécifier ce qui devrait être affiché dans les articles du menu comme suit :
- Positionnez Bind to sur AuthorsController.
- Positionnez Controller Key sur arrangedObjects.
- Positionnez Model Key Path sur lastName.
Enfin, configurez la liaison selectedObject pour spécifier la relation 1-pour-1, que ce menu pop-up permettra de changer, comme suit :
- Positionnez Bind to sur MediaAssetsController.
- Positionnez Controller Key sur arrangedObjects.
- Positionnez Model Key Path sur author (une relation 1-pour-1).
Maintenant, lorsque vous lancez votre application, un menu pop-up apparaît dans chaque cellule de la colonne de la table, affichant la valeur actuelle de la relation 1-pour-1. Lorsque l’utilisateur sélectionne un autre article dans le menu, le contrôleur change l’objet de destination de cette relation.
Suivez les mêmes étapes que celle décrites ci-dessus pour configurer un NSPopUpButton en tant que relation 1-pour-1 modifiable. Si vous implémenter une interface maître-détail et que ce bouton pop-up apparaît dans l’interface détail, alors positionnez la Controller Key de la liaison selectedObject sur selection, c’est à dire, sur l’objet en cours de sélection.
Filtrer en Utilisant un Contrôleur Personnalisé de Table
Cet article explique comment utiliser un champ de recherche et un contrôleur personnalisé de table pour filtrer une collection d’objets. Bien qu’en général vous utilisiez un champ texte en conjonction avec une vue de table pour implémenter ce style d’interface, les tâches abordées dans cet article ne sont pas limitées à ces composants.
Surpasser arrangeObjects:
La méthode arrangeObjects: trie le contenu du contrôleur de table en utilisant les descripteurs de tri en cours. Pour restreindre le contenu affiché à un sous-ensemble, vous surpassez arrangeObjects:, créez un nouveau tableau contenant le sous-ensemble puis appelez l’implémentation de la super-classe de la méthode arrangeObjects: pour fournir toute sorte de tri approprié.
L’implémentation de arrangeObjects: dans le Listing 1 effectue une recherche de type NSAnchoredSearch (recherche effectuée seulement sur les caractères du début ou à la fin de la chaîne. Si aucune correspondance n’est trouvée sur les caractères du début ou de la fin cela signifie que rien n’est trouvé, même si une correspondance de caractères apparaît ailleurs dans la chaîne.) sur la propriété “title”. Dans une recherche de type “anchored”, seuls les objets dont la propriété “title” correspond à searchString sont ajoutés au tableau retourné.
Listing 1 Implémentation du Filtrage de arrangeObjects:
- (NSArray *)arrangeObjects:(NSArray *)objects {
if (searchString == nil) {
return [super arrangeObjects:objects];
}
NSMutableArray *filteredObjects = [NSMutableArray arrayWithCapacity:[objects count]];
NSEnumerator *objectsEnumerator = [objects objectEnumerator];
id item;
while (item = [objectsEnumerator nextObject]) {
if ([[item valueForKeyPath:@"title"] rangeOfString:searchString options:NSAnchoredSearch].location != NSNotFound) {
[filteredObjects addObject:item];
}
}
return [super arrangeObjects:filteredObjects];
}
Mettre à Jour la Chaîne de Recherche
Vous implémentez la méthode d’action search: pour invoquer rearrangeObjects, ce qui déclenche l’invocation de la méthode arrangeObjects:.
Le Listing 2 montre une implémentation d’une action search:. La searchString est positionnée sur la valeur de la chaîne de l’objet sender et rearrangeObjects est appelée.
Listing 2 Mise à jour de searchString
- (void)search:(id)sender {
// set the search string by getting the stringValue
// from the sender
[self setSearchString:[sender stringValue]];
[self rearrangeObjects];
}
- (void)setSearchString:(NSString *)aString
{
[aString retain];
[searchString release];
searchString=aString;
}
@end
L’action search: est invoquée par un NSSearchField. La cible du champ de recherche est positionnée sur le contrôleur de table et l’action sur la méthode search:. Le champ de recherche devrait être configuré de façon à ne pas envoyer la chaîne tout entière lorsqu’elle change. Le fait de désactiver cette option provoque l’invocation de la méthode search: chaque fois qu’une touche de clavier est pressée dans le champ de recherche.
![]()
Texte original en anglais sur developer.apple.com : Cocoa Bindings
© Août 2004 - “mailto:thierry@projectomega.org”>Thierry pour Project:Omega
Chargement
Commentaires récents