[Résolu] Serialisation, Plist

Am_MeAm_Me Membre
septembre 2014 modifié dans API UIKit #1

Bonjour, à  tous


 


Voilà  ça fait un moment que je n'ai pas touché au développement iOS donc je suis un peu rouillé. J'ai cherché sur votre forum un "problème similaire" mais je n'ai rien trouvé.


 


Voilà  le fonctionnement de l'application :


En fait je suis en train de faire une application assez basique qui se connecte à  une page web, récupère un résultat (sous format xml) dans un NSData (à  travers NSUrlConnection ...). 


 


Voilà  je voudrais sérialiser des objets (de la même classe : classe personnalisée) : mais j'ai eu toujours un difficultés au niveau de l'optimisation du code et de la mémoire.


 


Car moi mon raisonnement actuelle c'est 


 


i = 0


pour chaque objet dans mon Array


       sauvegarder(objet,"objet%d.xml",i)


      i++


fin pour


 


Mais du coup si j'ai 1000 objets je vais devoir tous les sauvegarder. Ni aurais t'il pas un moyen de stocker je sais pas un NSDictionnary par exemple ? En gros les grouper dans un seul fichier serialiser. Dans une seul PLIST


 


PS : c'est ma troisième demande en moins de 20 minutes je m'en excuse :/ mais bon ça servira à  des personnes dans un futur proche


Réponses

  • AliGatorAliGator Membre, Modérateur
    Hello


    Je t'invite à  lire le Archives and Serialization Programming Guide qui explique très bien toutes les techniques pour sérialiser tout un arbre d'objets.


    Pour résumer je pense que dans ton cas implémenter le protocole NSCoder est la solution. Et du coup une fois que tu auras un NSArray de tes objets à  sérialiser tu utilises [NSKeyedArchiver archiveRootObject:tonArrayDObjets toFile] et basta !


    Tout est prévu dans iOS pour archiver facilement des (graphes d')objets donc autant utiliser le système tout fait :-)
  • Am_MeAm_Me Membre
    septembre 2014 modifié #3

    Merci.


    Ok je me renseigne du coup.


     


    Mais du coup que conseil-tu Property List, NSCoder, Core Data et pourquoi ?


     


    En fait j'aime bien quand l'api est simple et clair et quand je vais sur une page comme le lien que tu m'a passé je me perd dans la doc (je comprend l'anglais : niveau moyen) mais je suis habitué à  la java doc qui n'a rien à  voir.Question d'habitude


  • AliGatorAliGator Membre, Modérateur
    L'arbre de décision concernant la solution à  choisir dépend de ton contexte. Des pistes sur les questions à  se poser pour bien choisir sont évoquées il me semble dans ledit programming guide (PG).

    Les PLIST c'est bien si tes données à  stockées sont parmi les types autorisés dans les PLIST (String, Date, Data, ... je n'ai plus la liste complète en tête, elle est indiquée dans le PG, mais elle n'est pas bien longue).
    Du coup pour archiver par exemple un NSDictionary c'est bien, mais pour archiver un NSObject avec des @property, faut le convertir en NSDictionary puis stocker ce NSDictionary dans un PLIST (et recréer le NSObject à  partir du NSDictionary lors de la relecture). Par contre l'avantage c'est que c'est lisible ensuite par un éditeur de texte ou en ouvrant le fichier PLIST dans Xcode.

    Du coup pour des données (préférences, listes de valeurs à  charger comme des constantes dans ton appli, etc) c'est bien, mais pour un arbre d'objets plus complexes et qui sont plutôt des NSObject que des NSDictionary, c'est pas la solution adaptée.
    Dans ce cas il faut mieux passer par NSKeyedArchiver / NSKeyedUnarchiver (et implémenter le protocole NSCoder sur tes classes). C'est pas dur (et très bien expliqué dans le PG) et iOS gère ensuite tout tout seul (sérialisation, sauvegarde dans le fichier, éviter les redondances en cas de cycle dans ton arbre d'objets comme A qui référence B qui référence C qui référence A, ...)



    Après, tout cela c'est pour de la sérialisation sur disque de données, c'est plus orienté aussi pour quand tu veux sauvegarder des objets sur disque un peu comme tu sauvegarderais un document Word dans ton disque dur (niveau concept fonctionnel).

    Mais si tu veux travailler avec un vrai modèle de données (MCD - Modèle de Conception de Données), que tu as pensé façon diagramme UML, donc qui gère déjà  les relations entre les différents objets, qui gère les contraintes entre ces relations, si A peut être lié à  plusieurs B ou à  un seul, le fait que si A est détruit, est ce que les objets B qu'il contient / auxquels il est lié doivent être supprimés automatiquement aussi (relation de type "contenant") ou ont-ils leur vie propre (relation de type "référence"), et qui persiste entre les lancement de l'application (car en effet sous le capot il est sérialisé dans une base mais ça c'est un détail d'implémentation), alors oui CoreData est la solution qu'il te faut.

    Vu la description de ton application et de ton fonctionnel, d'ailleurs c'est effectivement bien + CoreData que je te conseille, comme ça tu auras tous ses avantages, à  savoir :
    • Un éditeur de modèle sympa, avec une représentation graphique des différentes entités
    • Une gestion des relations entre les entités, leur cardinalité, leur delete rule, etc
    • Tout le mécanisme de validation des objets
    • Le concept de "contexte", un peu comme des transactions SQL ou des branches GIT, permettant par exemple de créer un contexte CoreData le temps de parser ton JSON et de créer tes objets dans ce contexte, et de sauver tout le contexte d'un coup en base ensuite quand tu es sûr que ton JSON a fini d'être parsé et qu'il n'a pas d'erreur (ou de ne pas sauver le contexte et de le jeter à  la poubelle si tu te rends compte à  la fin de ton parsing que ton JSON est invalide, qui sait)
    • Tu peux faire des requêtes sur tes données, un peu comme des requêtes SQL. Genre si tu manipules des Voitures et des Personnes, tu peux faire une requête pour demander toutes les personnes dont le nom commence par A, ou toutes les voitures qui appartiennent à  des personnes de sexe masculin, etc.
    • Et plein d'autres choses cool dans CoreData
    L'avantage de CoreData, surtout si tu l'utilises avec MagicalRecord, c'est qu'une fois que tu as bien compris son principe de fonctionnement, tout le reste est géré pour toi. Toi tu manipules juste des objets (ce ne sont pas des NSObject mais des NSManagedObjects, mais bon c'est le même principe, ils ont des propriétés, tu les manipules comme tu manipules les objets métier que tu comptais créer si tu ne faisais pas de CoreData) et tu appelles "save" et ça sauve les données.

    Après, CoreData peut faire peur au début car il y a beaucoup de concepts à  appréhender d'un coup, moi même j'ai mis du temps à  m'y mettre. Jusqu'au jour où j'ai découvert MagicalRecord, qui m'a simplifié la vie à  un point inimaginable, rendant l'utilisation de CoreData enfantine.

    Je t'invite fortement à  regarder ma présentation des CocoaHeads Rennes #13 à  ce sujet, qui te permettra d'appréhender tout cela, et de commander à  utiliser CoreData sans toute la complexité qu'il y a à  apprendre autour avant, grâce à  MagicalRecord qui cache toute sa complexité.
  • Am_MeAm_Me Membre
    septembre 2014 modifié #5

    J'ai lu l'explication et je viens peut-être de comprendre vraiment l'avantage de CoreData


     


    Donc ce que tu es en train de me dire c'est que je peux dire :


     


    Par exemple la relation : Personne a N voitures et Une voiture appartient à  1 personne (pour simplifier)


    Du coup je peux mettre une règle pour dire si je supprimer Personne : je supprimer les N voiture aussi ?


     


     


    Sachant que j'ai de bonne connaissance en UML, SQL : du coup ça devrait pas être si difficile non ?


    Bon je vais regarder la présentation CocoaHeads :D


     


    _________________


     


    MAJ


     


    Mais en revenant sur l'exemple des voitures  et personnes : 


    Si je défini ma class person :



    @class person
    {
    String name,last_name,age;
    Array<Cars> myCars;
    }

    Et que je me contente de les stocker dans une NSArray puis de serialiser avec NSPropertySerialization 


    (Vu que sur la doc sur la page NSPropertySerialization Apple parle de NSData, NSString, NSArray, NSDictionary, NSDate)


     


    Ce n'est pas plus simple au final ? Que de définir des règles etc ... ?




  • J'ai lu l'explication et je viens peut-être de comprendre vraiment l'avantage de CoreData


     


    Donc ce que tu es en train de me dire c'est que je peux dire :


     


    Par exemple la relation : Personne a N voitures et Une voiture appartient à  1 personne (pour simplifier)


    Du coup je peux mettre une règle pour dire si je supprimer Personne : je supprimer les N voiture aussi ?




    Oui.


    Il y a les règles sur les suppressions. Le delete cascade par exemple, ou autre en fonction de tes besoins (si par exemple supprimer une voiture n'implique pas de supprimer la personne).

    J'en avais déjà  parlé rapidement ici :

    http://forum.cocoacafe.fr/topic/12030-magicalrecord-delete-withwithout-cascade/#entry114172

    J'avais quoté rapidement les 4 règles.

  • Am_MeAm_Me Membre
    septembre 2014 modifié #7

    Ah carrément ok. Mais moi je n'aurai pas besoin de supprimer les voitures dans mon application (même si ce ne sont pas des voitures en réalité bref) mais je saurai amené à  en rajouter par contre


     


    PS : J'ai mis à  jour mon commentaire au dessus


  • Am_MeAm_Me Membre
    septembre 2014 modifié #8

    Bon je m'autorise à  remonter le sujet :P


     


    J'ai effectué un NSCoding donc avec les KeyArchive et KeyUnArchive de mon singleton (Cf l'exemple avec des Articles dans mon post précédent).


     


    Voilà  en gros mon singleton contient une liste NSMutableSet, plus particulièrement, d'Articles : et un article contient aussi un objet imaginez un objet Toto (c'est difficile je sais).



    @class Article:NSObject
    {
    NSString *nom,*url,texte;
    Toto *toto;
    UIImage *image;
    }

    Donc j'ai dit que mon singleton pouvait : 



    - (id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if (!self) {
    return nil;
    }
    articleALire = [decoder decodeObjectForKey:@articleALire];
    return self;
    }

    - (void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:articleALire forKey:@articleALire];
    }

    Jusque la vous me suivez :D ?


     


    Ensuite je me suis rappelé dans le passé avoir eu un problème : bref le truc c'était que je devais dire que mes objets (articles puis toto) doivent aussi implémenter les 2 méthodes encode et decode


     


    C'est ce que j'ai fait : j'ai fait la même chose pour Article et la même chose pour Toto.


     


    Mais je me retrouve avec cette jolie erreur quand je relance l'application. Sachant qu'à  l'ouverture de l'application j'ouvre le fichier ou a été sauvegarder mon singleton (normalement j'ai fait un test et la fonction d'écriture me retourne que tout c'est bien passé mais pour la fonction de lecture c'est l'inverse)



    ApplicationArticle(28992,0x21f01a8) malloc: *** mach_vm_map(size=1327104) failed (error code=3)
    *** error: can't allocate region
    *** set a breakpoint in malloc_error_break to debug
    2014-09-13 22:17:28.014 ApplicationArticle[28992:60b] *** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '*** -[NSKeyedUnarchiver _decodePropertyListForKey:]: data is corrupt or object is too large to decode'
    *** First throw call stack:
    (
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException

    Voilà  comment je lis puis j'écris.



    Dans mon fichier Singleton.m

    - (BOOL)updateInFile
    {
    NSString *directoryPath = [[NSString alloc] initWithFormat:@%@/",@Documents/singleton_save];
    NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:directoryPath];
    BOOL success = [NSKeyedArchiver archiveRootObject:self toFile:documentsDirectory];

    if(success)
    NSLog(@OK JE VIENS DE SAVE);
    else
    NSLog(@Big fail);

    return success;
    }

    - (void)loadInFile
    {
    NSString *directoryPath = [[NSString alloc] initWithFormat:@%@/",@Documents/singleton_save];
    NSString *documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:directoryPath];
    Singleton *tmp = [NSKeyedUnarchiver unarchiveObjectWithFile:documentsDirectory];

    if(tmp)
    {
    NSLog(@Okay je l'ai charge);
    }
    else
    {
    NSLog(@No ok);
    }
    //Oui je fait un double test mais la c'est juste pour le debug :D
    if(tmp)
    favorite = [tmp getMaMutableSet];
    }


    PS : Alors dans mon objet Article en théorie j'ai (15 NSString, 1 NSMutableString, 1 NSMutableDictionnary, 2 UIImage) et mon objet Toto (14 NSString et 1 BOOL)


     


    ​Si c'est un problème de taille mémoire j'aurai un peu la  >:D B)  


  • Ah oui vous allez me dire pourquoi sauvegarde-tu le singleton surement.


    Car il contient bah mes articles qui ont été sélectionnés par l'utilisateur précédemment et je veux que quand il ouvre son appli il les retrouve. Rien de plus simple


  • AliGatorAliGator Membre, Modérateur
    Comment tu sauves les UIImage ?
  • Am_MeAm_Me Membre
    septembre 2014 modifié #11

    Le classique (pour moi) : mais j'en suis sur c'est du à  elles l'erreurs. 



    [encoder encodeObject:image forKey:@image];

    et à  la lecture



    image = [decoder decodeObjectForKey:@image];


    Vu que ça renvoi un NSData peut-être ou surement ça fait n'importe quoi du coup mon code la


  • MayerickMayerick Membre
    septembre 2014 modifié #12
    Oui les UIImage ne peuvent être stockées tel quel avec NSCoding, tu peux éventuellement stocker le nom de l'image et la retrouver comme ça, si ben sur tu en as la possibilité.


    Avec Core Data tu aurais facilement pu sauver une UIImage de type transformable, qui effectivement permet des stocker des NSData à  partir d'image. Autre détail en faveur de Core data, il ne me semble pas que tu puisses faire de sauvegarde incrémmentale avec NSCoding. En gros à  chaque fois que tu sauves ça écrase puis re- sauvegarde toutes les données, ça va quand t'en en as 4/5, mais à  partir du moment où il faut écraser et re-sauver des données lourdes comme des images, tes performances dans l'app peuvent s'en faire ressentir.
  • Am_MeAm_Me Membre
    septembre 2014 modifié #13

    Oui je comprend pour la sauvegarde. Pour le moment je fait une sauvegarde par action effectuée. Mais c'est juste pour tester et débuger. Mais je ferai un sauvegarde quand l'utilisateur aura appuyé sur le bouton home pour sortir de l'application.


    Bref. Du coup je suis forcé de passer par la sauvegarde ?


     


    Personnellement ça me va car je les sauvegarde déjà  sous le format jpg dans mon NSHomeDirectory/Documents donc du coup mon appli retrouve l'image associé à  chaque objet.


     


    Bref j'ai résolu mon problème déjà  en enlevant mon UIIMage du NSCoding. Par la suite j'ai découvert qu'il y avait une boucle infini  >:)  vraiment bizarre. Je faisais appel à  ma fonction de lecture dans ma fonction init



    - (id)init
    {
    self = [super init];

    if (self) {
    //Mes allocs ...

    //[self loadInFile]; => la raison de la boucle infini
    }

    return self;

    Du coup j'ai plutôt fait appel à  la fonction dans sharedInstance pour le moment. Et ça marche beaucoup mieux


     


     


    Par contre je ne comprend pas un truc. Ca marche mais ça m'intrigue. 


    Juste en exécutant cette ligne à  la lecture 



    [NSKeyedUnarchiver unarchiveObjectWithFile:documentsDirectory]; 

    dans ma classe Singleton fait une initialisation de mon objet ? Car c'est ce qu'il se passe là  et je suis SURPRIS  ???


     


    Car moi je me voyais plus faire un truc du genre : 



    Singleton *copy = [NSKeyedUnarchiver unarchiveObjectWithFile:documentsDirectory];
    [self copyFromObject:copy];


    //ou surcharger la méthode copy :
    self = [copy copy];

     

  • AliGatorAliGator Membre, Modérateur
    1) si tu veux sauvegarder les UIImage dans ton archive il faut d'abord les transformer en NSData. En effet UIImage ne se conforme pas au protocole NSCoding. Tu peux utiliser des fonctions comme UIImagePNGRepresentation ou UIImageJPGRepresentation pour se faire par exemple.


    2) évidemment que quand tu unarchive ton archive ça va instancier et appeller le init (ou plutôt le initWithCoder) de chaque objet. C'est le but même de la désérialisation, c'est de recréer les objets en mémoire donc les réinstancier et restaurer les valeurs sauvegardées sur ces nouvelles instances ;-)
  • 1) Ok je vais me renseigner sur ça : j'avais vu en plus la fonction PNG sur le net hier. Je vais me pencher dessus.


     


    2) D'accord donc j'ai pas besoins d'écrire plein de ligne car le unArchiver fait appel au init automatiquement. Donc pas besoin de la méthode copy etc ...


  • AliGatorAliGator Membre, Modérateur
    septembre 2014 modifié #16
    Bah non. Tu pensais que ça marchait comment en fait ? J'ai du mal à  suivre ta logique...


    Le NSKeyedUnarchiver va créer de nouvelles instances des classes que tu as archivées et va appeler son initialiseur spécialisé "initWithCoder:" (au lieu du init classique) pour te donner l'opportunité de restaurer les valeurs des propriétés que tu avais précédemment archivées.


    Ces objets que le NSKeyedUnarchiver créé (réinstancie) c'est déjà  des copies conformes des objets que tu avais sérialisés/archivés donc pourquoi tu courais ensuite faire ton truc chelou de copyFromObject ou je ne sais quoi ?!


    T'as lu le Archives and Serialization Programming Guide ?
  • En fait j'ai lu sur NSHipster j'aurai du surement regarder la doc.


    Oui ça j'ai compris que le keyUnarchiver fait appel à  



    - (id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if (!self) {
    return nil;
    }
    maListe = [decoder decodeObjectForKey:@maListe];
    return self;
    }

    Mais c'est juste que ça m'a surpris quand on encode on précise l'objet dans la fonction : Normal.


    Mais quand on décode on ne lui passe pas l'objet en paramètre et il se débrouille pour savoir que c'est sur mon Singleton.


    Un peu logique aussi si j'appel la fonction dans mon Singleton.m


  • AliGatorAliGator Membre, Modérateur
    septembre 2014 modifié #18
    Ce n'est pas parce que tu appelles la fonction dans ton Singleton.m qu'il sait qu'il faut créer un Singleton. Encore heureux. Tu peux désarchiver ton archive sérialisée depuis n'importe où.

    Non, c'est juste que quand tu sérialises et crée ton archive, il stocke aussi dans l'archive le type (la classe) de l'objet, justement pour pouvoir la recréer tout seul quand tu désarchive.
    Si tu veux plus de sécurité, et indiquer par code la classe que tu attends pour être sûr qu'il n'y aura pas de problème ou de crash (au cas où tu attendrais un NSArray mais qu'en fait dans l'archive c'est indiqué que c'est un NSDictionary par exemple, car un petit malin a altéré ton archive ou parce que tu as fait une erreur dans ton code), tu peux utiliser NSSecureCoding à  la limite.


    Sinon c'est plutôt une très mauvaise idée que de désérialiser ton Singleton lui-même dans le init de ce dernier (de désérialiser un objet A dans la méthode init de la classe A elle-même) : tu risques fort d'avoir une belle reccursivité (d'où ta boucle infinie plus haut d'ailleurs, j'imagine fort bien). Car dans le init de ton singleton, tu appelles NSKeyedUnarchiver, qui va créer une nouvelle instance de Singleton, qui va appeler son init, qui va appeler le NSKeyedUnarchiver, qui va créer une nouvelle instance de Singleton, qui va appeler init, ... etc

    Non en général :
    • Dans le cas où ce n'est pas un singleton, on sérialise tout l'objet, et on le recrée par exemple dans le application:DidFinishLaunchingWithOptions: ou un truc comme ça, ou désérialiser chaque objet dans l'objet parent qui est sensé le contenir (dans le init d'une classe "Garage", tu désérialiserais ton tableau de voitures pour l'affecter à  sa "@property NSArray* voitures" par exemple), mais certainement pas dans le init dudit objet, sinon forcément... boucle infinie
    • Dans le cas où c'est un singleton c'est un peu particulier, tu ne vas pas sérialiser le singleton lui-même car si tu veux ne garantir qu'il n'y ait qu'une seule instance de ton singleton (la sharedInstance), ça va pas le faire. En effet tu risques d'appeler la méthode sharedInstance (qui va s'assurer, au moyen d'un dispatch_once(...), qu'il n'initialise ton instance qu'une seule fois même si tu appelles sharedInstance 36 fois) d'un côté, et le NSKeyedUnarchiver lui il s'en fout de la méthode sharedInstance (ou sharedModel ou sharedService ou tu l'as appelé comme tu veux) lui il ne connait pas cette méthode et il va appeler directement initWithCoder, sas se soucier de l'unicité que tu souhaites préserver pour n'avoir qu'une seule instance. Au final tu vas te retrouver avec l'instance créée via sharedInstance, mais qui sera vide (propriétés non restaurées, juste créée comme la première fois), et une autre instance créée par le NSKeyedUnarchiver, avec ses propriétés restaurées, mais dont tu ne feras rien...
    Donc ce qu'il faut dans ton cas c'est plutôt de sérialiser non pas le Singleton lui-même mais chacune de ses propriétés, et dans le init du Singleton restaurer chacune de ces propriétés. Mais pas sérialiser le Singleton lui-même, car il ne faudrait pas que le NSKeyedUnarchiver recrée une instance de ta classe Singleton, au risque de créer une instance qui n'a rien à  voir (et au risque si tu mets le code appelant NSKeyedUnarchiver dans le init de ton Singleton lui-même, de faire une boucle infinie vu que dans ce cas le NSKeyedUnarchiver va réinstancier un objet Singleton et pas juste chacune des propriétés qu'il contient)
  • Je n'utilise pas le dispatch_once(..) mais 



    // Get the shared instance and create it if necessary.
    + (Work *)sharedInstance {
    if (sharedInstance == nil) {
    sharedInstance = [[super allocWithZone:NULL] init];
    }

    return sharedInstance;
    }

    Mais ça revient au même je pense.


     


     




     


    • Donc ce qu'il faut dans ton cas c'est plutôt de sérialiser non pas le Singleton lui-même mais chacune de ses propriétés, et dans le init du Singleton restaurer chacune de ces propriétés. Mais pas sérialiser le Singleton lui-même, car il ne faudrait pas que le NSKeyedUnarchiver recrée une instance de ta classe Singleton, au risque de créer une instance qui n'a rien à  voir (et au risque si tu mets le code appelant NSKeyedUnarchiver dans le init de ton Singleton lui-même, de faire une boucle infinie vu que dans ce cas le NSKeyedUnarchiver va réinstancier un objet Singleton et pas juste chacune des propriétés qu'il contient)

     




     


    Mais j'encode et je décode non pas le singleton en lui même mais ces propriété en faisant ça : 



    - (id)initWithCoder:(NSCoder *)decoder {
    self = [super init];
    if (!self) {
    return nil;
    }
    articleALire = [decoder decodeObjectForKey:@articleALire];
    return self;
    }

    - (void)encodeWithCoder:(NSCoder *)encoder {
    [encoder encodeObject:articleALire forKey:@favorite];
    }

    articleALire est une NSMutableSet.


  • AliGatorAliGator Membre, Modérateur
    Et tu appelles ton NSKeyedArchiver sur quel objet ?
  • Am_MeAm_Me Membre
    septembre 2014 modifié #21

    Ahh ...


     


    Sur self (Singelton)



    [NSKeyedArchiver archiveRootObject:self toFile:documentsDirectory];

    du coup je dois faire plutôt ?



    [NSKeyedArchiver archiveRootObject:articleAlire toFile:documentsDirectory];

  • AliGatorAliGator Membre, Modérateur
    Bah oui voilà .

    Car sinon tu archives self (donc ton instance de Singleton), donc tu archives l'instance de Singleton elle-même (qui va, pour s'archiver, appeler sa méthode encodeWithCoder: pour encoder ses propriétés sous-jacentes comme articleALire etc). Et si tu fais ça, ça veut dire qu'à  l'inverse quand tu vas ensuite demander de désarchiver ton archive, il va se charger de recréer une instance de Singleton (puisque ce Singleton tu l'as inclus dans l'archive), menant au problème décrit plus haut.

    Donc en effet, il faut plutôt que tu n'archives pas ton instance de Singleton dans ton archive, mais mettes seulement dans l'archive ses propriétés sous-jacentes, dans ton cas articleALire en effet.
  • Oui du coup c'est logique ce que tu dis. Ce que je faisais été assez dangereux et pas sécurisé. Du moins moins sécurisé que maintenant 


     


    Je regarderais le NSCodingSecure par la suite


Connectez-vous ou Inscrivez-vous pour répondre.