Table des matières du kit de Support | Index du Kit de Support |
BeOS fournit un protocole pour archiver et désarchiver des objets. Quand vous archivez un objet, vous enregistrez son état dans un BMessage qui peut être envoyé à une autre application, "applati" et sauvé dans un fichier, mis en cache dans la mémoire, et ainsi de suite. Le désarchivage fait l'opposé: il prend une archive BMessage et le transforme en un objet pleinement fonctionnel.
Le protocole d'archivage est représenté par la classe BArchivable. Beaucoup de classes BeOS héritent de BArchivable. Si vous créez vos propres classes et voulez qu'elles soient archivables, elles, aussi, doivent hériter (directement ou non) de BArchivable.
Les sections ci—dessous vous expliquent (1) comment archiver et désarchiver un objet, et (2) ce que vous devez faire pour créer votre propre classe archivable.
Pour archiver un objet BArchivable, vous créez un BMessage et le passez à la fonction Archive() de l'objet. Vous pouvez ensuite envoyer le message à une autre application ou, comme montré ci—dessous, écrire sa représentation "applatie" dans un fichier et pouvez le récupérer plus tard:
/* Archivage et stockage d'un BButton, sans vérification d'erreurs.*/ BMessage message; BButton *button; BFile file; button->Archive(&message); file.SetTo(filename, B_CREATE_FILE | B_WRITE_ONLY); message.Flatten(&file);
Pour désarchiver, vous prenez un objet archivé et le passez au constructeur de l'objet, ou, si vous ne connaissez pas la classe de l'objet ( nous en parlerons plus en détails plus tard), vous le passez à la fonction instantiate_object(). Le cas du constructeur est plus simple:
BMessage msg; BFile f; BButton *button; file.SetTo(filename, B_READ_ONLY); msg.Unflatten(&f); button = new BButton(&msg);
Invoquer le constructeur est excellent si vous connaissez la classe de l'objet que vous désarchivez. Mais considérez le cas où vous désarchivez un objet depuis un message que vous n'avez pas créer. Par exemple, dites vous que votre application affiche une vue qui est importé depuis une archive étrangère (envoyée depuis une autre application, ou chargée depuis un add-on). Pour désarchiverl'objet "inconnu", vous passez l'archive BMessage à instantiate_object(), et ensuite caster l'objet retourné (un BArchivable *) en quelque chose:
BView *foreignView; foreignView = dynamic_cast<BView *>(instantiate_object(&msg));
Vous ne connaissez toujours pas la classe de l'objet, et vous ne pouvez invoquer aucunes fonctions qui sont définies, mais au moins
Chaque classe archivable implemente Archive() pour enregistrer les propriétés d'un objet (données membres, objets "possédés", etc.) que cette classe definit. Les propriétés sont ajoutées comme des champs au BMessage argument. La plupart des implémentations ressemblent à ceci:
status_t MyClass::Archive(BMessage *archive, bool deep) { baseClass::Archive(archive, deep);1 archive->AddInt32("MyClass::Property1", property1);2 archive->AddString("MyClass::Property2", property2); ... if ( deep3 ) { BMessage childArchive; for (int32 i; i < CoundChildren(); i++ ) if ( childAt(i)->Archive(&childArchive, deep) == B_OK ) archive->AddMessage("children", &childArchive); } message->AddString("add_on", "application/x-CodeForThisObject");4 }
1 Premièrement, appelez la version hérité de Archive(). Ceci donne à toutes les classes ancêtres un droit d'enregistrement de toutes les propriétés qu'elles definissent. Si votre objet ne désire pas inclure les propriétés héritées, il doit plutôt invoquer la version de BArchivable:
BArchivable::Archive(archive, deep);
2 Ensuite, enregistrez les propriétés qui sont définies pour cette classe. Comment les champs du message sont nommés et typés dépend de la classe elle-même. C'est une bonne idée de donner à vos champs une sorte de préfixe pour éviter les collisions avec les champs définis par Be (dont les noms sont, malheureusement, un peu fortuits).
3 Le deuxième argument de Archive() indique si l'archive doit être profonde ou superficielle. Dans une archive profonde, une classe archive tous les objets qu'elle "possède"—approximativement, ces même objets que la classe est responsable d'effacer ensuite. L'enfant archivable doit aussi hérité de BArchivable.
4 Cette ligne enregistre la signature de la bibliothèque qui contient le code de l'objet. Si vous voulez que votre objet puisse être chargé dynamiquement par une quelconque autre application, vous devez ajouter la signature de la bibliothèque sous la chaîne "add_on". Vous n'avez pas à fournir la bibliothèque si vous tenez pas compte le chargement dynamique.
Si une clase n'a aucune données à archiver, il n'est pas nécessaire d'implémenter la fonction Archive().
Pour être désarchivable, une classe doit implémenter un constructeur qui prend un BMessage en argument, et doit implémenter la fonction statique Instantiate().
Un constructeur de désarchivage typique appelle la version héritée, et ensuite reconstitue les propriétés qui ont été ajoutées quand l'objet a été archivé:
MyClass::MyClass(BMessage *archive) : baseClass(archive) { int32 i; BMessage msg; BArchivable *obj; archive->FindInt32("MyClass::Property1", &property1); archive->FindString("MyClass::Property2", &property2); ... while ( data->FindMessage("children", i++, &msg) == B_OK)1 { obj = instantiate_object(&msg); childList->AddItem(dynamic_cast<ChildClass *>(obj)); } }
1 Vous n'avez pas besoin de vous demander si ...
La classe doit aussi implémenter la fonction statique Instantiate() (déclarée dans BArchivable), qui n'a pas besoin de rien faire de plus que d'appeler le constructeur acceptant une archive, et retourne un pointeur de type BArchivable. Par exemple:
BArchivable *TheClass::Instantiate(BMessage *archive) { if ( validate_instantiation(archive, "TheClass")) return new TheClass(archive); return NULL; }
La fonction validate_instantiation(), fournie par le kit de Support, est une vérification de sécurité qui permet d'être sure que l'objet BMessage est, en fait, une archive pour la classe désirée.
Pour désarchiver un BMessage, vous appelez la fonction instantiate_object() . Quand est passé en argument une archive de type BMessage, instantiate_object() regarde en premier lieu le nom dans le tableau de classe, trouve la fonction Instantiate() pour cette classe, et l'appelle. En cas d'échec, elle prend un autre nom dans le tableau de classe (en fonction de la hiérarchie d'héritage) et re—essaye.
instantiate_object() retourne une instance de BArchivable. Ensuite vous utilisez cast_as() pour caster l'objet dans une classe plus intérressante. Une session typique de désarchivage ressemble à quelque chose comme ceci:
/* archive est le BMessage que nous voulons transformer en objet. * Dans ce cas précis, nous voulons le transformer en une BView. */ BArchivable *unarchived = instantiate_object(archive); if ( unarchived ) { BView *view = cast_as(unarchived, BView); if ( view ) { . . . }
Il n'a pas encore été définit comment un hôte interagira avec une instance désarchivée d'une classe précédèment inconnue. C'est aux différents groupes de définir les points d'entrées et les protocoles, tel qu'il est fait pour un module add-on.
Table des matières du kit de Support | Index du Kit de Support |
Copyright © 2000 Be, Inc. All rights reserved..