2011-12-21 12 views
8

Jest to opis mojego problemu:Niektóre relacje CoreData zostaną utracone po zamknięciu aplikacji

dodaję (i potwierdzają one dodane) około 1400 relacji ładowanych z usługą mydła w CoreDat. Po zamknięciu aplikacji i ponownym jej otwarciu niektóre z relacji zostają utracone; Widzę tylko około 800 z nich (chociaż to się zmienia). Ponadto nie otrzymuję żadnych błędów.

i teraz, więcej szczegółów:

mam obiektu o nazwie User który zawiera informacje na temat usług użytkownik zapisanych; wygląda to mniej więcej tak:

@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 

W części kodu gdy stosuje się dane, relacje są zapisane tak:

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); 
      } 
     } 
    } 

Sprawa jest to, że zostały sprawdzone z debugger i widzę, że wszystkie ponad 1400 relacji są dodawane, ale gdy aplikacja jest resetowana i są one przywracane przez self.user.services, otrzymuję tylko około 800 obiektów.

Dlaczego tak się mogło stać? Ktoś już to miał?

Z góry dziękuję.


UPDATE:

Ludzie wciąż sugeruje, że nie używam danych Core poprawnie, ale problemem jest to, że dane zostaną utracone po ponownym uruchomieniu aplikacji. Nie ma absolutnie żadnego problemu z nim podczas korzystania z niego. Używam danych podstawowych, które są poprawne, ponieważ mogą zawierać ograniczoną dokumentację i przykłady, które otrzymujesz od Apple.

+0

Zapisujesz kontekst w każdej iteracji? Czemu? I gdzie dodajesz obiekt usługowy do użytkownika? –

+0

Robiłem to na końcu iteracji, ale robiłem to tak, aby zobaczyć, czy to był problem. Dodaję go do 'userServices', który jest NSMutableSet pobranym od użytkownika. Próbowałem również użyć 'addServicesObject' z podobnymi wynikami. – pablisco

+0

Ì myślę, że źle rozumiesz działanie podstawowych danych.Najpierw należy wstawić do db obiekt, a następnie dodać go za pomocą addServicesObject: jako relację do użytkownika lub dodać ją w zestawie pomocniczym, a następnie ustawić relację od użytkownika do usług za pomocą wartości addServices: (NSSet *); method –

Odpowiedz

11
NSMutableSet *userServices = self.user.services; 

... 

      [userServices addObject:service]; 

Nie można tego zrobić. self.user.services nie zwraca zmiennego zestawu. Właśnie do tego służy ta metoda addServicesObject. Zmień drugą linię do:

  [self.user addServicesObject:service]; 

Z dokumentacji Apple:

Ważne jest, aby zrozumieć różnicę między wartościami zwracanych przez dot akcesor i mutableSetValueForKey:. mutableSetValueForKey: zwraca zmienny obiekt proxy. Jeśli zmutujesz jego zawartość, wyemituje odpowiednie powiadomienia o zmianach wartości klucz-wartość (KVO) dla relacji. Akcelerator kropki po prostu zwraca zestaw. Jeśli manipulować zestawu, jak pokazano w tym fragment kodu:

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

Przypomnijmy, że kropka po prostu wywołuje metodę dostępowej, więc z tych samych powodów:

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

+0

Skomentowane wcześniej, ale także nie problem. Działa, ponieważ niektóre obiekty są przywracane po ponownym uruchomieniu. 'self.user.services' zwraca NSMutableSet, w rzeczywistości dodanie metody pomocnika addServicesObject jest opcjonalne. 'user.services' jest równoważne [user valueForKeyPath: @" user.services "]. W przeciwnym razie, dlaczego niektóre z nich zostaną zapisane? – pablisco

+0

Nie powinieneś używać tego zmiennego narzędzia accessor, jak poniżej: 'NSMutableSet * userServices = [self mutableSetValueForKeyPath: @" user.services "];'? – paulbailey

+0

@paulbailey Nah, tak samo jak robienie 'user.service' – pablisco

3

I ve ten sam problem, ale po ustawieniu odwrotnej relacji, wszystko jest w porządku. Mam nadzieję, że pomoże to w zbadaniu tego problemu.

+0

Próbowałem tego, ale nadal mam brakujące relacje :( – pablisco

+0

Wow, to prawda w moja sprawa, co do cholery, dlaczego CD nie uratuje związku tylko dlatego, że nie ma odwrotnej relacji skonfigurowane? Istnieją ważne przypadki, w których chcesz uniknąć odwrotnej relacji.I oczywiście najwyraźniej nie zostały naprawione w ciągu ostatnich 4 lat. – udondan

0

W końcu rozwiązałem go, używając niestandardowego NSPredicate, który pobiera usługi, używając jednego specjalnego parametru, który ustawiam w usługach, gdy są one dodawane przez użytkownika.

Działa, chociaż nie jest idealny.

1

Okej, spójrzmy na objawy tutaj. Wprowadzasz zmiany w obiektach w kontekście, ale po ponownym uruchomieniu aplikacji istnieją pewne, ale nie wszystkie z tych zmian.

Może to tylko oznaczać, że zmiany te nie są zapisywane w magazynie trwałym. Ponieważ widzisz niektóre ze zmian, wywołujesz metodę save:, ale Core Data nie rozpoznaje wszystkich obiektów jako potrzebnych do zapisania.

To prowadzi nas do sposobu wykonywania zmian w rzeczonych obiektach. Czy wprowadzasz zmiany w sposób zgodny z KVO? Core Data opiera się na KVO, aby dowiedzieć się, jakie zmiany zaszły, a zatem, jakie zmiany należy utrzymać. Jeśli zmienisz obiekty w stylu innym niż KVO, będą wyglądały na zmienione podczas ich badania, ale Core Data nie będzie wiedziała, że ​​te zmiany istnieją, i dlatego nie będzie wiedziała, że ​​musi je utrzymywać.

chciałbym zmienić swój kod w następujący sposób, zapewniając obiekt Service ma zależność odwrotną pleców do User (i że związek jest nazywany user, a część 1-M):

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

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

polega ta na fakt, że Core Data zajmie się dla ciebie obydwoma końcami relacji, gdzie jest ustawiona odwrotna zależność. Oczywiście, jeśli jest to relacja wiele do wielu, kod jest nieco inny, ale wciąż używamy metod zgodnych z KVO do wprowadzania zmian.

[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

Jest to relacja MM.Uznam teraz, że nie mogę użyć bezpośredniego dostępu kropka, aby dodać obiekty i zrozumiałem, że CD zajmuje odwrotne relacje.Ale próbowałem użyć 'addServicesObject' zamiast punktu dostępu z podobnymi wynikami – pablisco

+0

Wygląda na to, że sprawdzasz, czy obiekt jest już w zestawie, zanim go dodasz. Myślę, że to prawdopodobnie niepotrzebny kompleks ity. Po prostu dodaj usługę do zestawu i pozwól, aby Cocoa i Core Data zdecydowały, czy to już jest) ("NSMutableSet" nie pozwala na dodanie tego samego obiektu dwa razy) oraz b) czy jest zmiana, która wymaga zapisania do magazyn trwały. Niech frameworki wykonają pracę dla ciebie, gdzie tylko mogą. – paulbailey

+0

Dodałem to jako oddzielną poprawkę, ponieważ otrzymywałem duplikaty.Ale to już inna historia (chyba). Wiem, że nie możesz mieć tego samego obiektu, ale możesz mieć dwa obiekty z tymi samymi danymi. A operacja zapisu była tylko próbą sprawdzenia, czy to był problem. Nie oszczędzałem ich wcześniej. – pablisco

0

Miałem ten sam problem związek z innym podmiotem utracone za każdym razem, gdy ponownie uruchomić aplikację. Szukałem godzin. W końcu znalazłem problem. Oświadczam, że moja relacja jako Transient spowodowała problem.

enter image description here

0

Dla mnie sprawa była odwrotna zależność

Jest mój model

enter image description here

Wszystkie mają to umożliwić odwrotną zależność takiego:

enter image description here

enter image description here

Powiązane problemy