2011-12-21 19 views
8

Questa è la panoramica del mio problema:Alcune relazioni CoreData vengono persi dopo la chiusura app

sto aggiungendo (e confermano che vengono aggiunti) circa 1400 rapporti caricati da un servizio di sapone in CoreDat. Dopo aver chiuso l'app e averla riaperta, alcune delle relazioni sono perse; Ne vedo solo circa 800 (anche se varia). Inoltre, non ricevo errori.

e ora, ulteriori dettagli:

Ho un oggetto chiamato User che ha informazioni su servizi di un utente sono salvati; sembra qualcosa di simile:

@interface OosUser : NSManagedObject 

    + (OosUser *) userFromSlug: (NSString *) slug; 
    @property (nonatomic, retain) NSString *name; 
    @property (nonatomic, retain) NSString *slug; 
    @property (nonatomic, retain) NSMutableSet /* Service */ *services; 
    - (void) addServicesObject: (Service *)service; 
    - (void) removeServicesObject: (Service *) service; 

@end 

@implementation User 

    @dynamic name; 
    @dynamic slug; 
    @dynamic services; 

    static NSString *fetchPredicate = @"slug = %@"; 

    + (User *) userFromSlug:(NSString *)slug 
    { 
     User *result = [super objectWithPredicate: fetchPredicate, slug]; 
     if (!result) { 
      result = [super create]; 
      result.slug = slug; 
     } 
    return result; 
    } 

@end 

Nella parte del codice in cui vengono utilizzati i dati, i rapporti vengono salvati in questo modo:

NSMutableSet *userServices = self.user.services; 

for (Service *service in servicesToAdd) { 
     [self.services addObject: service]; 
     bool contained = false; 
     for (Service *userService in userServices) { 
      if ((contained = [userService.slug isEqualToString:service.slug])) { 
       break; 
      } 
     } 
     if (!contained) { 
      // [userServices addObject:service]; 
      [self.user addServicesObject: service]; 
      NSError *error = nil; 
      if (![[service managedObjectContext] save:&error]) { 
       NSLog(@"Saving failed"); 
       NSLog(@"Error: %@", [error localizedDescription]); 
      }else { 
       NSLog(@"Registered service %d: %@", self.services.count, service.slug); 
      } 
     } 
    } 

Il caso è che ho controllato con il debugger e posso vedere che tutte le oltre 1400 relazioni vengono aggiunte, ma quando l'app viene resettata e vengono ripristinate tramite self.user.services ottengo solo circa 800 oggetti.

Perché questo potrebbe accadere? Qualcuno ha avuto questo prima?

Grazie in anticipo.


UPDATE:

La gente continua suggerendo che non sto usando Core Data correttamente, ma il problema è che i dati vengono persi dopo il riavvio dell'applicazione. Non ci sono assolutamente problemi durante l'utilizzo. Sto usando Core Data nel modo corretto in quanto potrebbe essere fornita la documentazione limitata e gli esempi che ottieni da Apple.

+0

Si salva il contesto in ogni iterazione? Perché? E dove aggiungi l'oggetto servizio all'utente? –

+0

Lo stavo facendo alla fine dell'iterazione, ma ho fatto questo per vedere se quello era il problema. Lo aggiungo a 'userServices', che è un NSMutableSet recuperato dall'utente. Ho anche provato a usare 'addServicesObject' con risultati simili. – pablisco

+0

Ì pensa di sbagliare come funzionano i dati di base.Devi prima inserire in db l'oggetto e poi aggiungerlo con addServicesObject: come relazione all'utente o aggiungerlo in un set ausiliario e quindi impostare la relazione da utente a servizi con addServices: (NSSet *) valore; metodo –

risposta

11
NSMutableSet *userServices = self.user.services; 

... 

      [userServices addObject:service]; 

Impossibile farlo. self.user.services non restituisce un set mutabile. Ecco a cosa serve il metodo addServicesObject. Modificare la seconda linea a:

  [self.user addServicesObject:service]; 

Da documentazione di Apple:

E 'importante capire la differenza tra i valori restituiti dalla funzione di accesso punto e da mutableSetValueForKey:. mutableSetValueForKey: restituisce un oggetto proxy mutabile. Se si modifica il suo contenuto, emetterà le notifiche di modifica del valore chiave (KVO) appropriato per la relazione. L'access point dot restituisce semplicemente un set. Se si manipola il set come mostrato in questo frammento di codice:

[aDepartment.employees addObject:newEmployee]; // do not do this! then KVO change notifications are not emitted and the inverse relationship is not updated correctly.

Ricordiamo che il punto invoca semplicemente il metodo di accesso, quindi per gli stessi motivi:

[[aDepartment employees] addObject:newEmployee]; // do not do this, either!

+0

Prima commentato, ma anche non il problema. Funziona poiché alcuni oggetti vengono ripristinati dopo il riavvio. 'self.user.services' restituisce un NSMutableSet, infatti l'aggiunta del metodo helper addServicesObject è facoltativa. 'user.services' è equivalente a [user valueForKeyPath: @" user.services "]. Altrimenti come mai alcuni di loro vengono salvati? – pablisco

+0

Non dovresti usare l'accessorio set mutabile, come questo: 'NSMutableSet * userServices = [self mutableSetValueForKeyPath: @" user.services "];'? – paulbailey

+0

@paulbailey Nah, come fare 'user.service' – pablisco

3

I' Ho lo stesso problema, ma dopo aver impostato la relazione inversa, tutto è di nuovo OK. Spero che questo aiuti a indagare su questo problema.

+0

L'ho provato ma mi mancano ancora le relazioni :( – pablisco

+0

Wow, questo è vero in il mio caso, che diamine, perché il CD non salverà la relazione solo perché non esiste una relazione inversa? Ci sono casi validi in cui si desidera evitare una relazione inversa e ovviamente non è stato corretto negli ultimi 4 anni. – udondan

0

Alla fine l'ho risolto utilizzando un custom NSPredicate che recupera i servizi utilizzando un parametro speciale che imposto sui servizi quando vengono aggiunti da un utente.

Funziona anche se non è l'ideale.

1

Ok, diamo un'occhiata ai sintomi qui. Stai apportando modifiche agli oggetti all'interno di un contesto, ma quando riavvii l'app, ci sono alcune ma non tutte queste modifiche.

Questo può solo significare che queste modifiche non vengono scritte nell'archivio permanente. Poiché stai vedendo alcune delle modifiche, stai chiamando il metodo save:, ma Core Data non riconosce tutti gli oggetti che devono essere salvati.

Questo ci porta a come si stanno eseguendo le modifiche a detti oggetti. Stai apportando le modifiche in modo conforme allo standard KVO? I dati di base si basano su KVO per sapere quali cambiamenti si sono verificati, e quindi quali cambiamenti devono persistere. Se modifichi gli oggetti in modo non KVO, sembreranno che vengano modificati quando li esamini, ma i Dati principali non sapranno che queste modifiche esistono e quindi non sapranno che deve persisterle.

vorrei modificare il codice come segue, fornendo l'oggetto Service ha la relazione inversa di nuovo alla User (e che il rapporto si chiama user, e parte di un 1-M):

[servicesToAdd setValue:self.user forKey:@"user"]; 

NSError *error = nil; 
if (![[service managedObjectContext] save:&error]) { 
    NSLog(@"Saving failed"); 
    NSLog(@"Error: %@", [error localizedDescription]); 
} 

Questo si basa sul fatto che i dati di base si prenderanno cura di entrambi gli estremi della relazione per te, in cui viene impostata una relazione inversa. Naturalmente, se si tratta di una relazione molti-a-molti, il codice è leggermente diverso, ma utilizziamo ancora i metodi conformi a KVO per apportare le modifiche.

[servicesToAdd setValue:self.user forKey:@"user"]; 

for (Service *service in servicesToAdd) { 
    [user addServicesObject:service]; 
} 

NSError *error = nil; 
if (![[service managedObjectContext] save:&error]) { 
    NSLog(@"Saving failed"); 
    NSLog(@"Error: %@", [error localizedDescription]); 
} 
+0

È una relazione MM. Riconosco ora che non posso usare direttamente la Access Point per aggiungere gli oggetti e stavo anche comprendendo che il CD si occupa delle relazioni inverse. Inoltre, ho provato a usare 'addServicesObject' invece dell'accessorio dot con risultati simili – pablisco

+0

Sembra che tu stia controllando se l'oggetto è già nel set prima di aggiungerlo Credo che questo sia probabilmente un complesso non necessario lità. Basta aggiungere il servizio al set e lasciare che Cocoa e Core Data determinino se è già presente (un 'NSMutableSet' non consente di aggiungere lo stesso oggetto due volte) eb) se c'è un cambiamento che deve essere salvato nel negozio persistente. Lascia che le strutture facciano il lavoro per te dove possono. – paulbailey

+0

L'ho aggiunto come correzione separata perché stavo ottenendo i duplicati.Ma questa è una storia diversa (credo). So che non puoi avere lo stesso oggetto ma puoi avere due oggetti con gli stessi dati. E l'azione di salvataggio era solo un tentativo di vedere se quello era il problema. Non li stavo salvando prima. – pablisco

0

Ho avuto lo stesso problema il rapporto con un'altra entità perso ogni volta che riavvio l'app. Ho cercato per ore. Alla fine ho trovato il problema. Ho dichiarato che il mio rapporto come Transient, ha causato il problema.

enter image description here

0

Per me, il problema era la relazione inversa

C'è il mio modello

enter image description here

Tutti hanno è quello di consentire relazione inversa in questo modo:

enter image description here

enter image description here

Problemi correlati