Stockage d'objects personnalisés avec Core Data

J'essaie de stocker un NSMutableArray composé de VOs (NameVO) avec des données de base mais en levant l'exception suivante:

'NSInvalidArgumentException', reason: '-[NameVO encodeWithCoder:]: unrecognized selector sent to instance 0x1096400a0' 

Mon NameVO est juste un simple object de valeur, qui étend NSObject et contient deux champs, une string et un NSMutableArray qui contient lui-même des strings. Il contient également une fonction de comparaison.

J'essaye de préparer ceci pour être stocké comme un type d'atsortingbut transformable de CD avec ('noms' est mon tableau NameVO):

 NSData *tempNamesData = [NSKeyedArchiver archivedDataWithRootObject:names]; 

Ma question est: que dois-je faire pour que NameVO soit accepté par NSKeyedArchiver pour le convertir avec succès en un NSData?

Je ne veux pas que NameVO étende NSManagedObject parce que je ne peux pas l'instancier et l'initialiser directement.

Comme votre exception l'indique, vous devez implémenter le protocole NSCoding dans votre class et vous devez replace deux methods:

 - (void)encodeWithCoder:(NSCoder *)aCoder; - (id)initWithCoder:(NSCoder *)aDecoder; 

Il devrait sortinger votre problème.

// ÉLARGI

 - (id)initWithCoder:(NSCoder *)aDecoder { self = [super init]; if (self) { _formId = [aDecoder decodeObjectForKey:@"FormID"]; } return self; } - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:self.formId forKey:@"FormID"]; } 

Utilisez cette initWithCoder et encodeWithCode . J'espère que cela fonctionnera pour vous. cela fonctionne pour moi dans le même problème que vous avez … Utilisez cet exemple de code

 -(id)initWithCoder:(NSCoder *)aDecoder { if(self = [super init]){ storePlaylist=[aDecoder decodeObjectForKey:@"storePlaylist"]; playlistName=[aDecoder decodeObjectForKey:@"playlistName"]; } return self; } -(void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:storePlaylist forKey:@"storePlaylist"]; [encoder encodeObject:playlistName forKey:@"playlistName"]; } 

Maintenant que nous sums en 2017, il est préférable d'utiliser le protocole NSSecureCoding plus sûr à la place du protocole NSCoding plus ancien et less sûr. Les changements d'implémentation sont minimes:

1) assurez-vous que votre class déclare sa conformation à NSSecureCoding

 @interface MyClass : NSObject<NSSecureCoding> @property (nonatomic, strong) NSNumber *numberProperty; @property (nonatomic, strong) NSSsortingng *ssortingngProperty; @end 

2) Le protocole NSSecureCoding héberge les deux mêmes methods de méthode d'instance dans le protocole NSCoding, plus une méthode de class supplémentaire, +supportsSecureCoding . Vous devrez append cette méthode, ainsi que légèrement modifier votre méthode -initWithCoder :.

 @implementation MyClass // New Method for NSSecureCoding. Return YES. + (BOOL)supportsSecureCoding { return YES; } // Your Encode Method Can Stay The Same, though I would use NSSsortingngFromSelector whenever possible to get the keys to ensure you're always getting what you're looking for. - (void)encodeWithCoder:(NSCoder *)aCoder { [aCoder encodeObject:self.numberProperty forKey:NSSsortingngFromSelector(@selector(numberProperty))]; [aCoder encodeObject:self.ssortingngProperty forKey:NSSsortingngFromSelector(@selector(ssortingngProperty))]; } // Slightly updated decode option - (instancetype)initWithCoder:(NSCoder *)aDecoder { self = [super init]; if (self) { self.numberProperty = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:NSSsortingngFromSelector(@selector(numberProperty))]; self.ssortingngProperty = [aDecoder decodeObjectOfClass:[NSSsortingng class] forKey:NSSsortingngFromSelector(@selector(ssortingngProperty))]; } } @end 

Notez que -decodeObjectOfClass de -decodeObjectOfClass:withKey: vous oblige à spécifier la class que vous attendez de recevoir. C'est une façon beaucoup plus sûre de faire les choses.

Ensuite, pour stocker cet object décodable dans CoreData, créez simplement un object Managed qui contient un atsortingbut NSData et quelques informations d'identification (une string, une date, un identifiant, ou un nombre ou quelque chose)

 @interface MyClassMO : NSManagedObject @property (nonatomic, strong) NSSsortingng *identifier; @property (nonatomic, strong) NSData *data; @end @implementation MyClassMO @dynamic identifier; @dynamic data; @end 

En pratique, cela ressemblerait à ceci:

 - (void)storeObject:(MyClass *)object withIdentifier:(NSSsortingng *)identifier { NSData *objectData = [NSKeyedArchived archivedDataWithRootObject:object]; NSManagedObjectContext *moc = ... // resortingeve your context // this implementation relies on new NSManagedObject initializers in the iOS 10 SDK, but you can create it any way you typically create managed objects MyClassMO *managedObject = [[MyClassMO alloc] initWithContext:moc]; managedObject.data = objectData; managedObject.identifier = identifier; NSError *error; [moc save:&error]; } - (MyClass *)resortingeveObjectWithIdentifier(NSSsortingng *)identifier { NSManagedObject *moc = ... // resortingeve your context // This also relies on iOS 10 SDK's new factory methods available on NSManagedObject. You can create your request any way you typically do; NSFetchRequest *request = [MyClassMO fetchRequest]; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"identifier = %@", identifier]; request.predicate = predicate; NSError *error; NSArray<MyClassMO *> *results = [moc executeFetchRequest:request withError:&error]; // if you're only storing one object per identifier, this array should only be 1 object long. if not, you'll need to decide which object you're looking for. you also might want to implement an overwrite policy or a delete before store type thing. MyClassMO *managedObject = results.firstObject; NSData *objectData = managedObject.data; MyClass *object = [NSKeyedUnarchiver unarchiveObject:objectData]; return object; } 

Cette solution est évidemment un peu simplist, comment et quand vous stockez des choses dans la database est à vos besoins, mais l'idée principale est que vous devez vous assurer que votre class personnalisée est conforme à NSSecureCoding, et que vous ' Vous devez créer une class d'objects gérés distincte pour stocker et récupérer vos données.