101 votes

Stockage des objets personnalisés dans un NSMutableArray dans NSUserDefaults

J'ai récemment essayé de stocker les résultats de la recherche de mon iPhone dans la NSUserDefaults collection. J'ai aussi l'utiliser pour sauvegarder des informations d'enregistrement de la avec succès, mais pour une raison d'essayer de stocker mes NSMutableArray de l'Emplacement personnalisé classes en revient toujours vide.

J'ai essayé de convertir le NSMutableArray à un NSData élément de ce post, mais j'obtiens le même résultathttp://stackoverflow.com/questions/350848/possible-to-save-an-integer-array-using-nsuserdefaults-on-iphone)

Les exemples de code que j'ai essayé sont:

Enregistrer:

[prefs setObject:results forKey:@"lastResults"];
[prefs synchronize];

ou

NSData *data = [NSData dataWithBytes:&results length:sizeof(results)];
[prefs setObject:data forKey:@"lastResults"];

ou

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:results];
[prefs setObject:data forKey:@"lastResults"];

Charge:

lastResults = (NSMutableArray *)[prefs objectForKey:@"lastResults"];

ou

NSData *data = [prefs objectForKey:@"lastResults"];
memcpy(&lastResults, data.bytes, data.length);

ou

NSData *data = [prefs objectForKey:@"lastResults"];
lastResults = [NSKeyedUnarchiver unarchiveObjectWithData:data];

Après avoir suivi les conseils ci-dessous j'ai également mis en œuvre NSCoder dans mon objet (ignorer la surutilisation de NSString ses temporaire):

#import "Location.h"


@implementation Location

@synthesize locationId;
@synthesize companyName;
@synthesize addressLine1;
@synthesize addressLine2;
@synthesize city;
@synthesize postcode;
@synthesize telephoneNumber;
@synthesize description;
@synthesize rating;
@synthesize priceGuide;
@synthesize latitude;
@synthesize longitude;
@synthesize userLatitude;
@synthesize userLongitude;
@synthesize searchType;
@synthesize searchId;
@synthesize distance;
@synthesize applicationProviderId;
@synthesize contentProviderId;

- (id) initWithCoder: (NSCoder *)coder
{
    if (self = [super init])
    {
    	self.locationId = [coder decodeObjectForKey:@"locationId"];
    	self.companyName = [coder decodeObjectForKey:@"companyName"];
    	self.addressLine1 = [coder decodeObjectForKey:@"addressLine1"];
    	self.addressLine2 = [coder decodeObjectForKey:@"addressLine2"];
    	self.city = [coder decodeObjectForKey:@"city"];
    	self.postcode = [coder decodeObjectForKey:@"postcode"];
    	self.telephoneNumber = [coder decodeObjectForKey:@"telephoneNumber"];
    	self.description = [coder decodeObjectForKey:@"description"];
    	self.rating = [coder decodeObjectForKey:@"rating"];
    	self.priceGuide = [coder decodeObjectForKey:@"priceGuide"];
    	self.latitude = [coder decodeObjectForKey:@"latitude"];
    	self.longitude = [coder decodeObjectForKey:@"longitude"];
    	self.userLatitude = [coder decodeObjectForKey:@"userLatitude"];
    	self.userLongitude = [coder decodeObjectForKey:@"userLongitude"];
    	self.searchType = [coder decodeObjectForKey:@"searchType"];
    	self.searchId = [coder decodeObjectForKey:@"searchId"];
    	self.distance = [coder decodeObjectForKey:@"distance"];
    	self.applicationProviderId = [coder decodeObjectForKey:@"applicationProviderId"];
    	self.contentProviderId = [coder decodeObjectForKey:@"contentProviderId"];
    }
}

- (void) encodeWithCoder: (NSCoder *)coder
{
    [coder encodeObject:locationId forKey:@"locationId"];
    [coder encodeObject:companyName forKey:@"companyName"];
    [coder encodeObject:addressLine1 forKey:@"addressLine1"];
    [coder encodeObject:addressLine2 forKey:@"addressLine2"];
    [coder encodeObject:city forKey:@"city"];
    [coder encodeObject:postcode forKey:@"postcode"];
    [coder encodeObject:telephoneNumber forKey:@"telephoneNumber"]

177voto

Brad Larson Points 122629

Pour le chargement d'objets personnalisés dans un tableau, c'est ce que j'ai utilisé pour saisir le tableau:

NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:@"savedArray"];
if (dataRepresentingSavedArray != nil)
{
    NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
    if (oldSavedArray != nil)
        objectArray = [[NSMutableArray alloc] initWithArray:oldSavedArray];
    else
        objectArray = [[NSMutableArray alloc] init];
}

Vous devez vérifier que les données renvoyées par l'utilisateur par défaut n'est pas nul, parce que je crois désarchivage de nul provoque un blocage.

L'archivage est simple, en utilisant le code suivant:

[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:objectArray] forKey:@"savedArray"];

Comme f3lix souligné, vous avez besoin pour faire de votre objet personnalisé conforme à la NSCoding protocole. Ajout des méthodes comme suit devrait faire l'affaire:

- (void)encodeWithCoder:(NSCoder *)coder;
{
    [coder encodeObject:label forKey:@"label"];
    [coder encodeInteger:numberID forKey:@"numberID"];
}

- (id)initWithCoder:(NSCoder *)coder;
{
    self = [super init];
    if (self != nil)
    {
        label = [[coder decodeObjectForKey:@"label"] retain];
        numberID = [[coder decodeIntegerForKey:@"numberID"] retain];
    }   
    return self;
}

0voto

f3lix Points 13634

Voir "Pourquoi NSUserDefaults pu sauver NSMutableDictionary dans le SDK de l'iPhone? "(http://stackoverflow.com/questions/471830/why-nsuserdefaults-failed-to-save-nsmutabledictionary-in-iphone-sdk)


Si vous le souhaitez (de)sérialiser des objets personnalisés, vous avez à assurer les fonctions de sérialiser les données (NSCoding protocole). La solution de vous référer à des œuvres avec l'int tableau, parce que le tableau n'est pas un objet mais un espace contigu de mémoire.

0voto

Gcoop Points 1684

Selon moi, qu'il semble que le problème avec votre code n’est pas sauver le tableau des résultats. Sa charge les données essaient d’utiliser

Ceci renverra le tableau spécifié par la clé.

0voto

Bill Dudney Points 2953

Je déconseille d'essayer de stocker des trucs comme ça dans les paramètres par défaut db.

SQLite est assez facile à ramasser et à utiliser. J'ai un épisode de l'une de mes screencasts (http://pragprog.com/screencasts/v-bdiphone) sur un simple wrapper que j'ai écrit (vous pouvez obtenir le code sans avoir à acheter le SC).

C'est beaucoup plus propre pour stocker les données de l'application dans l'espace de l'application.

Tout ce que dit si il a encore un sens pour mettre ces données dans la db par défaut, puis voir le post f3lix posté.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X