2009-02-01 21 views
17

Stellen Sie sich eine CoreData-Entität vor (z. B. searchEngine).
NSManagedObjectContext verwaltet einige "Instanzen" dieser Entität.
Der Endbenutzer kann seinen "standard searchEngine" mit einem NSPopupButton auswählen.
Die selected object von NSPopupButton sollte an die NSUserDefaults gebunden werden.
Das Problem:CoreData-Entitäten in NSUserDefaults speichern

1) @try {speichern}

a) Wenn Sie versuchen, die ausgewählte "instance" direkt zu speichern, um NSUserDefaults es so etwas wie das kommt:

-[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) Wenn Sie versuchen, die "Instanz" in NSData umzuwandeln kommt so:

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

So Irgendeine Idee, wie man diese Entitäten in Plist-kompatible Daten bringt?

2) @try {registerDefaults}

Normalerweise sind die registerDefaults: Methode wird in + (void)initialize umgesetzt. Das Problem besteht darin, dass diese Methode aufgerufen wird, bevor CoreData die gespeicherten Entitäten aus seiner Datenbank lädt. Also kann ich keinen Standard auf ein nicht existierendes Objekt setzen, oder?

Ich weiß, lange Fragen ... aber: try {[me liefern: details]}; D

Antwort

6

Sie würden nicht eine Kerndateneinheit und speichern Sie es versuchen wollen und zu archivieren. Stattdessen würden Sie den Schlüssel oder ein anderes bekanntes Attribut speichern und zum Abrufen der Entität verwenden, wenn die Anwendung gestartet wird.

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... 
} 

diese Weise können Sie den Namen in den Benutzereinstellungen zu speichern und das Unternehmen bei Bedarf holen:

Einige Beispiel-Code (etwas aus dem Beispiel in der Core Data Programming Guide geschrieben modifiziert).

+0

Mmh. Weißt du, warum 'array! = Nil' aber' [array count] <0' ... es nicht funktionieren will ... – papr

+0

Wenn array! = Nil dann gibt es keinen Fehler, aber es kann auch keine Datensätze geben returned ([array count] == ​​0) ... [array count] <0 kann * nie * auftreten, da die Count-Nachricht einen NSUInteger-Typ zurückgibt. Der Compiler löscht höchstwahrscheinlich einen solchen Test ([array count] <0). –

+0

Ja. Ich meinte ([array count] == ​​0). Das tut mir leid. Ich wollte nur ausdrücken, dass es in diesem Array nichts gibt. ;) – papr

33

Wenn Sie einen Verweis auf einen bestimmten verwalteten Objekt speichern müssen, verwenden Sie die URI Darstellung seiner verwalteten Objekt-ID:

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

Anschließend können Sie die URL speichern, um Benutzereinstellungen.

das verwaltete Objekt abzurufen, verwenden Sie:

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

Der einzige Nachteil ist, dass Sie, dass das ursprüngliche verwaltete Objekt-ID dauerhaft gewährleisten muss - das ist kein Problem, wenn Sie die bereits gespeichert haben Objekt, alternativ können Sie obtainPermanentIDsForObjects:error: verwenden.

+3

Ich denke, das ist eine saubere Lösung. Ein kleiner Zusatz, wie die Dokumentation von NSUserDefaults sagt, Sie müssen NSURL-Objekte als NSData archivieren. Also sei vorsichtig, NSURL nicht so zu retten, wie es ist. Ich habe gerade diesen Fehler gemacht und wurde immer Null, als ich versuchte, das Objekt zu finden. Beachten Sie auch, dass NSUserDefaults eine setURL: forKey: -Methode hat. Ich glaube nicht, dass dies momentan für iPhone OS verfügbar ist. – tilish

+7

setURL: forKey: ist verfügbar in iOS 4.0 und höher – djskinner

+1

BE BEACHTEN SIE! Tilish's Kommentar ist wichtig, die richtige Lösung ist hier: http://StackOverflow.com/a/516735/1780492 Ohne dies erhalten Sie die Fehlermeldung: "versuchen Sie, nicht-Eigentum Liste Objekt x-coredata:" – BootMaker

6

Hier ist der sauberste und kürzeste Weg, dies derzeit mit den in 4 hinzugefügten Methoden setURL und getURL zu tun.0 zu vermeiden, zusätzliche Anrufe zu NSKeyedUnarchiver und 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]; 
}