Save et Save As "à la main"
Herve
Membre
Bonjour,
Dans un projet, j'ai dû renoncer à utiliser NSDocument parce que je ne pouvais utiliser le multi-fenêtrage. J'y crée des NSMenu (voir discussion à côté).
J'ai donc fait ceci pour sauvegarder :
et pour ouvrir cela :
Cela marche très bien.
La NSString "nomDeFichier" a @property et @synthesize, comme vous l'aviez compris.
Dans ma méthode Save (sans passer par le NSSavePanel donc), la méthode
refuse de marcher. J'ai pourtant bien instancié avec alloc et init le NSString dans la méthode init de la classe. Selon vous, pourquoi cela ne marche pas?
J'ai aussi vu, en bossant là dessus la classe NSURL ainsi qu'une discussion dans ce forum à ce sujet : j'ai essayé de sauvegardé un NSURL à la place d'un NSString, sans succès pour l'instant. Le problème me semble venir du fait que je n'utilise pas NSSavePanel. Des vérifications avec NSLog montrent que "nomDeFichier" est bien conservé et porte bien tout le chemin vers l'archive.
J'ai passé déjà plusieurs heures là dessus, je sèche. Quelqu'un connaà®t peut-être le truc? (C'est maintenant une application à une seule fenêtre).
Dans un projet, j'ai dû renoncer à utiliser NSDocument parce que je ne pouvais utiliser le multi-fenêtrage. J'y crée des NSMenu (voir discussion à côté).
J'ai donc fait ceci pour sauvegarder :
- (IBAction) sauvegardeDocument : (id) sender{<br /> [self sauveDessinEnCours];//méthode pour mettre dans mesDonnees le travail en cours, marche TB.<br /> int runResult;<br /> NSSavePanel * savePanel = [NSSavePanel savePanel]; <br /> //diverses optimisations de la fenêtre<br /> runResult = [savePanel runModal];<br /> if (runResult == NSOKButton){<br /> [self setNomDeFichier :[savePanel filename]];//nomDeFichier est une String de la classe AppController<br /> [NSKeyedArchiver archiveRootObject:mesDonnees toFile:nomDeFichier ];<br /> //mesDonnees : instance d'une classe stockant tout mon travail.<br /> }<br />}
et pour ouvrir cela :
<br />[self setNomDeFichier :[openPanel filename]];<br />mesDonnees = [NSKeyedUnarchiver unarchiveObjectWithFile:nomDeFichier]; <br />[mesDonnees retain];<br />
Cela marche très bien.
La NSString "nomDeFichier" a @property et @synthesize, comme vous l'aviez compris.
Dans ma méthode Save (sans passer par le NSSavePanel donc), la méthode
[NSKeyedArchiver archiveRootObject:mesDonnees toFile:[self nomDeFichier ]];
refuse de marcher. J'ai pourtant bien instancié avec alloc et init le NSString dans la méthode init de la classe. Selon vous, pourquoi cela ne marche pas?
J'ai aussi vu, en bossant là dessus la classe NSURL ainsi qu'une discussion dans ce forum à ce sujet : j'ai essayé de sauvegardé un NSURL à la place d'un NSString, sans succès pour l'instant. Le problème me semble venir du fait que je n'utilise pas NSSavePanel. Des vérifications avec NSLog montrent que "nomDeFichier" est bien conservé et porte bien tout le chemin vers l'archive.
J'ai passé déjà plusieurs heures là dessus, je sèche. Quelqu'un connaà®t peut-être le truc? (C'est maintenant une application à une seule fenêtre).
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Pas de soucis ici pour sauvegarder que ce soit dans une application Document based ou pas.
Me sauvegarde sans souci un fichier qui pourra être désarchivé pour retrouver @À archiver plus tard. Pour que ça ne marche pas, même si rootObject est à nil ça marche, il faut donc que mon chemin ne soit pas valide.
Tu devrais peut être regarder par là (et les droits en écriture) à vérifier avec NSFileManager et isWritableFileAtPath: ...
Avec les NSKeyedArchiver on a peu de souci justement, c'est parfois plus compliqué quand on veut utiliser directement writeToFile avec un tableau ou un dictionnaire (on ne peut mettre que des objets qui sont "all property list objects (NSString, NSData, NSArray, or NSDictionary objects)"
hth
Il faudra vraiment que je m'y fasse à la gestion de la mémoire. Là encore, je n'avais pas mis un petit "retain" qui fait tout. Aussi le NSLog fonctionnait bien dans la méthode "ouvrir" mais plus une fois en dehors. J'ai lu la doc, mais il y a encore du chemin. J'ai d'ailleurs des problèmes parfois à l'ouverture, etc. Que c'est dur!
Merci, problème résolu donc. Ahhhhh!
La pente est raide mais une fois arrivé sur le premier plateau ça va beaucoup mieux
Et le panorama peut valoir le coup d'oeil (je manque d'éléments de comparaison).
Mais pour remplir la chaudière il faut des objets et ceux ci ont une vie qu'il faut assimiler, n'hésite pas à revoir souvent les simples principes jusqu'à ce qu'ils deviennent une seconde nature. C'est quand même pas si dur : new, alloc, retain, copy tu dois relacher quand tu n'en as plus besoin. Pour les autres tu laisses faire Cocoa.. Un objet créé par une méthode de classe ne vit que dans la méthode en cours sauf s'il est retenu par un autre (c'est souvent là que ça coince: quand l'autre disparaà®t..).
Utilise le débugger pour suivre la référence de tes objets à l'intérieur de la méthode en exécution ( ! 0x0 ).
Et utilise Instruments pour voir si tu oublies d'en relâcher ou, cas inverse, quand ton appli plante sur un "EXC_BAD_ACCESS" qui signe souvent un objet parti quand on compte sur lui.
Enfin les propriétés (retain | copy) et @synthesize peuvent aider à bien gérer ça mais il ne faut pas oublier de remplir la méthode dealloc en fonction de ce que tu as choisi comme type de propriété. Et utiliser self.monObjetDeClasse = monNouvelObjet à chaque fois.
Si tu veux te rafraà®chir la mémoire ;-)
Là par exemple, j'avais pas bien compris...
A propos de la méthode "autorelease", si j'ai bien compris la doc, il faut lancer quelque part un "NSAutoreleasePool". Est-ce une méthode qu'il faut appeler lors de la manipulation du programme, ou est-ce qu'elle gère le truc tout seul? Je comprends qu'il faut, lorsqu'on aura utilisé les données en "autorelease" lancer le "NSAutoreleasePool" à un moment. Hum... >:(
J'ai aussi du mal à comprendre les "Performance tools". L'outil "Allocation" par exemple fait des beaux graphes bleus, mais pour s'y retrouver... Ou bien cela sert simplement à vérifier que les objets se créent puis disparaissent bien "globalement". Enfin, à chaque jour ses progrès, je saurai faire ceux-là aussi...
Ceci dit, Cocoa + XCode + NextStep + CoreImage (et bientôt + CoreAudio), ça dépote!
Ouvre le fichier main.m de n'importe quelle application si tu veux voir la déclaration du pool.
Sur ce ==> dodo pour moi !
Tu as compris la doc mais tu ne l'as peut être pas lue assez souvent encore
La phrase que j'ai mis du temps à trouver mais qui m'a fait l'impression d'avoir trouvé l'interrupteur dans le noir:
Dans le lien que je te donnais, onglet AutoreleasePool
Quand tu cliques sur un bouton pour lancer une méthode AppKit va créer son bassin et quand tu sortiras de la méthode tous les objets que tu auras créés disparaitront si tu n'as pas prévu (dans ton code) de les garder. Par exemple il va pouvoir afficher ton tabeau de chaà®nes mais s'il doit le redessiner (et il redessine souvent sans qu'on s'en aperçoive, cliquer sur la fenêtre peut suffire) ça crashe !
Je t'accorde qu'Instruments n'est pas simple. Je m'en sers surtout pour trouver les zombies auquel cas il repasse au premier plan avec une bulle à l'endroit où le programme a crashé qui porte l'adresse mémoire de l'objet défaillant que tu peux retrouver en double cliquant sur l'étiquette qui contient cette adresse ou en filtrant comme il est montré ici Descendre jusque "Searching in the Detail Panel" (dans une doc toujours plutôt copieuse ;/
Pour le lancer il suffit de choisir "Run with Performance Tool" du menu "Run" et "Zombies" dans le sous menu.
Attention tu perds tes logs dans la console Xcode (mais tu les as dans la console qui est dans le sous dossier Utilitaires du dossier Applications)