Archivage & Co

gibet_bgibet_b Membre
06:29 modifié dans API AppKit #1
Comme je l'ai indiqué dans un précédent post, je suis en plein découverte du Cocoa. Pour cela j'utilise le livre "Cocoa par la pratique" qui a du être utilisé par un certain nombre d'entre vous. Cependant je me pose des questions dont je n'arrive pas à  trouver la réponse.

Je suis au chapitre 13 et j'essaie de répondre à  l'exercice qui demande de pouvoir dessiner des ovales (j'ai remplacé par des traits) en choisissant leur emplacement et leur taille, et éventuellement, d'implémenter l'enregistrement et la lecture des fichiers.

Je suis donc retourné en arrière et relu le chapitre sur l'Archivage. Le problème c'est que l'implémentation dans ce chapitre se fait dans une application de type Document Based. Or mon application est une "Cocoa Application". Aussi je ne sais pas où implémenter les méthodes initWithcoder, encodeWithCoder (j'ai pensé à  PaintView.m mais j'ai un problème avec le initWithCoder qui vient remplacer initWithFrame) et encore moins dataRepresentationOfType et loadDataRepresentation...

J'ai regardé le tutoriel "Echecs" qui traite de l'enregistrement des parties, et qui est une "Cocoa Application" mais cela n'utilise pas l'archivage mais une autre méthode d'enregistrement, d'après ce que j'ai compris. Quelles sont donc les différences ? Peut-on utiliser l'archivage avec un application qui n'est pas "Document Based" ?

Pardon pour toutes ces questions de newbie, et merci de l'accueil !

Réponses

  • Eddy58Eddy58 Membre
    06:29 modifié #2
    Bien sûr, tu peux utiliser l'archivage dans tout les types d'applications. En faites le mieux déjà  c'est d'établir le schéma MVC dans ton appli, en implémentant une classe modèle, dans laquelle tu pourras aussi mettre tes méthodes d'archivage. Voilà , si tu as des questions sur la marche à  suivre, n'hésites pas. :) 
  • WIMPWIMP Membre
    06:29 modifié #3
    NSCoder est approprié pour archiver un objet compliqué qui contient des références à  plusieurs autres objets. Chaque objet archive automatiquement ses sous-objets, et on obtient automatiquement une description en NSData de l'arbre (du graph) de l'objet.
    Dans les cas simples on s'en passe facilement. Dans le tuto Echecs j'enrgistre un NSArray, qui est accepté directement par la methode writeToFile, donc pas besoin de NSCoder.
  • gibet_bgibet_b Membre
    06:29 modifié #4
    Merci à  vous deux de m'avoir répondu !

    J'ai donc essayé d'utiliser la méthode du tutoriel dans mon application. Malheureusement, il me renvoie une erreur lorsque j'essaie de faire "Fichier/Enregistrer sous" : "Can't save file '/Users/jean-baptistebournisien/Desktop/Sans titre.dessin': No such file or directory"

    Forcément que le fichier n'existe pas, puisque je veux le créer...

    Voici ma méthode savePanelDidEnd :
    - (void)savePanelDidEnd:(NSSavePanel *)sheet
                returnCode:(int)returnCode
                contextInfo:(void  *)contextInfo
    {
    NSString *filetype = [sheet requiredFileType];
    NSArray *recordTabTraits;

    if (returnCode == NSCancelButton) return;

    recordTabTraits = [NSMutableArray arrayWithArray:tabTraits];

    if ([filetype isEqualToString:@dessin])
    {
    if ([recordTabTraits writeToFile:[sheet filename] atomically:NO]==NO)//erreur à  l'écriture
    {
    NSRunAlertPanel(nil,
    @Can';t save file '%@';: %s",nil,nil,nil,
    [sheet filename],
    strerror(errno));
    }
    else // sauvegarde effectuée
    {
    //On mémorise le chemin courant pour pouvoir le réutiliser dans (IBAction)save:
    curPath = [sheet filename];
    }
    }
    return;
    }


    Une idée ?

    D'avance merci, désolé pour ces questions de newbie !!!
  • AliGatorAliGator Membre, Modérateur
    avril 2006 modifié #5
    Je pense qu'il ne faut pas se baser sur errno pour connaà®tre le type d'erreur.
    Du coup l'erreur que tu as "No such file or directory" ne correspondrait pas du tout à  l'erreur que tu as effectivement, ce qui voudrait dire que le problème ne viens pas du tout de là .
    Enfin c'est une hypothèse parce qu'en fait je ne sais pas où tu pourrais récupérer le code d'erreur sinon, mais bon vu que perso j'utilise très peu errno (faut dire que souvent je n'affiche les messages d'erreurs que lorsque j'ai un NSError à  disposition ;))

    Vérifie que ton NSDictionary ne contient bien que des types d'objets qui peuvent être écrits dans un fichier plist : NSData, NSDate, NSNumber, NSString, NSArray, ou NSDictionary.
    Si tu as d'autres types que ceux-là  dans ton tabTraits, il faut les convertir (en pasasnt par ds NSCoder) dans un type supporté par les fichiers plist.


    Oh, et PS : Pour quelqu'un qui se qualifie de "newbie", je trouve que tu te débrouilles plutôt bien Et en plus tu as le mérite de chercher avant de poser la question, du moins il me semble, donc tu n'as pas à  t'excuser, un forum est fait pour ça :)
  • gibet_bgibet_b Membre
    06:29 modifié #6
    En fait, tabTraits n'est pas un NSDictionnary mais un NSMutableArray. Cela dit, c'est recordTabTraits que j'essaie d'enregistrer dans le fichier qui est quand à  lui un NSArray. Donc à  priori pas de problème.

    C'est embêtant si le code d'erreur ne veut rien dire...  ???

    En ce qui concerne ma newbizitude  :) il est vrai que ce n'est pas la première fois que je m'essaie à  la programmation (j'ai même des diplômes pour cela) mais je trouve que le développement en Cocoa est tout de même assez différent des différents langages que j'ai pu essayer jusqu'à  maintenant (Delphi, PHP, VB, Java, C/C++). C'est pour cela que j'ai l'impression de patauger un peu par moment. Faut dire que cela fait aussi un bout de temps que je n'avais pas entrepris d'apprendre un langage de programmation par moi-même. Enfin bref...
  • AliGatorAliGator Membre, Modérateur
    06:29 modifié #7
    Re-salut  <3 <br />
    Bon alors oui pardon en effet c'est un NSArray et pas un NSDictionary que tu essayes d'enregistrer, mais ça ne change rien au problème : est-ce que ton NSArray contient bien que des objets enregistrables dans un plist, et ceci dans toutes les "profondeurs" de ton NSArray ?

    Par exemple si tu as un NSArray de NSDictionnary et que tes NSDictionary contiennent par exemple entre autres des NSColor, ça n'ira pas car NSColor n'est pas enregistrable dans un plist... qu'ils soient directement à  la "racine" de ton NSArray ou dans un sous-élément, ou sous-sous-...-sous-élément ;)
  • gibet_bgibet_b Membre
    06:29 modifié #8
    Okkkk !!! J'ai compris, j'ai sans doute trouver le problème... En effet, dans mon NSArray, ce sont des NSPoint. Je vais creuser cette piste, qui se révelera sans doute bonne, je vous tiens au courant.

    J'avais pas capté (c'était pourtant évident) qu'il fallait que les éléments d'un NSArray soit également d'un type encodable.

    Merci 1000 fois !
  • Eddy58Eddy58 Membre
    avril 2006 modifié #9
    Il faut utiliser la classe NSArchiver, plus d'explications ici et là . :)
  • WIMPWIMP Membre
    06:29 modifié #10
    dans 1146080569:

    Okkkk !!! J'ai compris, j'ai sans doute trouver le problème... En effet, dans mon NSArray, ce sont des NSPoint.


    Un truc pratique pour stocker des NSPoint dans une NSString est d'utiliser NSPointFromString et NSStringFromPoint. Il n'y a plus qu'à  faire un NSArray de ces strings pour les enregistrer.
    Plus généralement, pour stocker plusieurs chose différentes dans une même string, par exemple un entier un float et un NSPoint, il est pratique d'utiliser componentsSeparatedByString: en conjonction avec intValue, floatValue, et NSPointFromString
  • gibet_bgibet_b Membre
    06:29 modifié #11
    Merci pour cette astuce, je vais essayer ! 
  • AliGatorAliGator Membre, Modérateur
    06:29 modifié #12
    Ah c'est "bizarre" cette technique, WIMP... enfin je veux dire... "original" quoi.
    J'avais pas pensé à  NSPointFromString et NSStringFromPoint pour l'archivage (je les utilise plutôt pour l'affichage en général), mais c'est vrai que c'est pas bête :)

    Par contre pour les objets plus complexes, qui contiennent plusieurs composantes etc, plutôt que componentsSeparatedByString moi je préfère faire un NSDictionary, pas toi ?
    Quitte à  créer des NSNumber pour encapsuler les int, float, ... puisque c'est fait pour.
    Je trouve qu'un dictionnaire est plus approprié pour décrire des données et donc les archiver ;)


    Enfin bon y'a pas de méthode meilleure qu'une autre, donc c'est comme tu le sens JB.
    Et puis si y'a que des NSPoints, la méthode de WIMP est aussi simple. C'est plus quand t'as des "gros" objets que le dico devient utile.
  • Eddy58Eddy58 Membre
    06:29 modifié #13
    Pourquoi s'embêter à  faire des conversions, et tout le code qui va avec, alors que les APIs proposent le nécessaire pour faire l'archivage/désarchivage en deux lignes ? ???
  • WIMPWIMP Membre
    06:29 modifié #14
    dans 1146350728:

    Pourquoi s'embêter à  faire des conversions, et tout le code qui va avec, alors que les APIs proposent le nécessaire pour faire l'archivage/désarchivage en deux lignes ? ???


    Disons que c'est "culturel": on n'aime pas trop changer ses habitudes, et il faut apprendre à  utiliser NSCoder, NSArchiver, etc... :)

    Pour répondre à  Aligator:
    Jusqu'à  présent je n'ai utilisé NSDictionary que pour enregistrer des préférences.
    Je trouve NSDictionary assez lourd à  manier, et je ne vois pas très bien la nécessité des paires clef-valeur pour enregistrer des données.
    Puisque de toutes façons le problème se ramène à  traduire ces données en NSData, j'essaie de placer mes données dans des structures C standard que je liste dans des NSArray, comme dans mon tuto Echecs.
    La méthode componentsSeparatedByString revient aussi à  créer une structure.

    Finalement je pense qu'il n'y a pas de methode d'archivage idéale, à  chacun de trouver celle qui lui convient le mieux.
    Enfin, je crois que pour organiser les données l'essentiel à  prendre en compte est aussi et surtout l'efficacité du code qui les manipule, en termes de simplicité et de vitesse d'exécution.
  • 06:29 modifié #15
    Il n'y a pas de méthode idéale, c'est sur. Mais il y en a qui sont moins bonnes que d'autres. Changer ses habitudes est dur, mais d'un autre coté, pourquoi vouloir apprendre un environnement aussi singulier que Cocoa, mais sans changer ses habitudes?

    Si tu t'intéresses un peu au NSCoder, tu verras que ce n'est pas plus dur que de stocker des données dans une string. Là  où tu fais [anArray addObject:NSStringFromPoint(aPoint)] avec un coder "normal", tu fais simplement [coder encodePoint:aPoint]. En procédant de la sorte, tu peux mettre des objets dans un tableau et sauver le tableau avec writeToFile:atomically: directement, sans n'avoir aucun travail de conversion à  faire. Je ne parle là  que de l'écriture, mais la lecture est tout aussi simple.

    Sinon effectivement, le dico n'est pas la solution la plus adéquate (mais c'est celle qui offre le plus de souplesse), mais par rapport à  la solution de la string, je ne vois vraiment pas pourquoi tu ne veux pas utiliser un tableau, tu n'auras pas plus de contraintes (=la contrainte d'ordre), mais par contre tu peux stocker des objets bien plus complexes (conformes à  NSCoding).
  • WIMPWIMP Membre
    06:29 modifié #16
    Je ne doute pas de la supériorité technique de NSCoder et NSArchiver. Le problème n'est pas que je ne veuille pas m'y mettre. Mais en tant que retraité, et programmant pour mon plaisir, j'ai bien droit à  un peu de paresse, non?  :)
  • 06:29 modifié #17
    ça dépend comment tu définis la paresse ;)

    Pour ma part c'est "profitons de ce que les autres ont fait".
Connectez-vous ou Inscrivez-vous pour répondre.