2009-02-01 6 views
17

Imaginez une entité CoreData (par exemple nommée searchEngine).
NSManagedObjectContext gère certaines "instances" de cette entité.
L'utilisateur final sera en mesure de sélectionner son "standard searchEngine" avec un NSPopupButton.
Le selected object de NSPopupButton doit être lié à NSUserDefaults.
Le problème:Enregistrer les entités CoreData dans NSUserDefaults

1) @try {} sauver

a) Si vous essayez d'enregistrer sélectionné "instance" directement NSUserDefaults il arrive quelque chose comme ceci:

-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value ' (entity: searchEngine; id: 0x156f60 ; data: { 
    url = " http://google.de/ "; 
    someAttribute = 1; 
    name = "google"; 
})' of class 'searchEngine'.

b) Si vous essayez de convertir le "instance" à NSData vient ceci:

-[searchEngine encodeWithCoder:]: unrecognized selector sent to instance 0x1a25b0

Ainsi une idée de comment obtenir ces entités dans une donnée compatible avec le plist?

2) @try {} registerDefaults

Habituellement la méthode registerDefaults: est mis en œuvre + (void)initialize. Le problème ici est que cette méthode est appelée avant que CoreData charge les entités sauvegardées de sa base de données. Donc, je ne peux pas définir un défaut à un objet inexistant, non?

Je sais, longues questions ... mais: try {[me fournir: détails]}; D

Répondre

6

Vous ne voudriez pas essayer d'archiver une entité de données de base et le stocker. Au lieu de cela, vous devez stocker la clé ou un autre attribut connu et l'utiliser pour récupérer l'entité au démarrage de l'application.

quelques exemples de code (légèrement modifié par l'exemple affiché dans le Core Data Programming Guide):

NSManagedObjectContext *moc = [self managedObjectContext]; 
NSEntityDescription *entityDescription = [NSEntityDescription 
    entityForName:@"SearchEngine" inManagedObjectContext:moc]; 
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; 
[request setEntity:entityDescription]; 

NSPredicate *predicate = [NSPredicate predicateWithFormat: 
    @"engineName LIKE[c] '%@'", selectedEngineName]; 
[request setPredicate:predicate]; 

NSError *error = nil; 
NSArray *array = [moc executeFetchRequest:request error:&error]; 
if (array == nil) 
{ 
    // Deal with error... 
} 

De cette façon, vous enregistrez le nom dans les paramètres utilisateur par défaut et allez chercher l'entité si nécessaire.

+0

Mmh. Savez-vous pourquoi 'array! = Nil' mais' [array array] <0' ... il ne veut pas travailler ... – papr

+0

Si array! = Nil alors il n'y a pas d'erreur mais il n'y a peut-être pas d'enregistrements retourné ([array count] == ​​0) ... cependant, [array count] <0 ne peut * jamais * se produire puisque le message count renvoie un type NSUInteger. Le compilateur supprime probablement un tel test ([array count] <0). –

+0

Oui. Je voulais dire ([nombre de tableaux] == 0). Désolé. Je voulais seulement exprimer qu'il n'y a rien dans ce tableau. ;) – papr

33

Si vous devez stocker une référence à un objet géré spécifique, utilisez la représentation URI de son objet géré ID:

NSURL *moIDURL = [[myManagedObject objectID] URIRepresentation]; 

Vous pouvez ensuite enregistrer l'URL par défaut d'utilisateur.

Pour récupérer l'objet géré, vous utilisez:

NSManagedObjectID *moID = [myPersistentStoreCoordinator managedObjectIDForURIRepresentation:moIDURL]; 
NSManagedObject *myManagedObject = [myContext objectWithID:moID]; 

La seule réserve est que vous devez vous assurer que l'ID d'objet géré d'origine est permanente - ce n'est pas un problème si vous avez déjà enregistré le objet, vous pouvez également utiliser obtainPermanentIDsForObjects:error:.

+3

Je pense que c'est une solution soignée. Une petite addition, comme dit la documentation pour NSUserDefaults, vous devez archiver les objets NSURL comme NSData. Alors faites attention de ne pas sauver NSURL comme il est. Je viens de faire cette erreur et j'ai continué à être nul quand j'ai essayé de récupérer l'objet. Notez également que NSUserDefaults a une méthode setURL: forKey:. Je ne pense pas que cela soit disponible pour iPhone OS pour le moment. – tilish

+7

setURL: forKey: est disponible dans iOS 4.0 et versions ultérieures – djskinner

+1

BE AWARE! Le commentaire de tilish est important, la bonne solution est ici: http://stackoverflow.com/a/516735/1780492 Sans cela vous obtiendrez un message d'erreur: "tentative d'insertion de l'objet de liste de non-propriétés x-coredata:" – BootMaker

6

Voici le moyen le plus propre et le plus court de le faire en utilisant les méthodes setURL et getURL ajoutées en 4.0 pour éviter les appels supplémentaires à NSKeyedUnarchiver et NSKeyedArchiver:

Setter:

+ (void)storeSomeObjectId:(NSManagedObjectID *)objectId 
{ 
    [[NSUserDefaults standardUserDefaults] setURL:[objectId URIRepresentation] 
              forKey:@"someObjectIdKey"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 
} 

Getter:

+ (SomeManagedObject *)getObjectByStoredId 
{ 
    NSURL *uri = [[NSUserDefaults standardUserDefaults] URLForKey:@"someObjectIdKey"]; 
    NSManagedObjectID *objectId = [self.persistentStoreCoordinator managedObjectIDForURIRepresentation:uri]; 
    SomeManagedObject *object = [self.managedObjectContext objectWithID:objectId]; 
} 
Questions connexes