22

Moje kakao/aplikacja ma kontekst zarządzanego obiektu w głównym wątku. Kiedy muszę aktualizować swoje dane mój program:Core Data łączy dwa obiekty zarządzane obiekty

  1. Zacznij nowy wątek
  2. Otrzymuj nowe dane z serwera
  3. Utwórz nowy zarządzanego obiektu Context
  4. Wyślij zgłoszenie do głównego wątku w celu połączenia się z dwóch kontekst

jest to funkcja, która odbierać powiadomienia w głównym wątku

- (void)loadManagedObjectFromNotification:(NSNotification *)saveNotification 
{ 
    if ([NSThread isMainThread]) { 
     [self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification]; 
    } else { 
     [self performSelectorOnMainThread:@selector(loadManagedObjectFromNotification:) withObject:saveNotification waitUntilDone:YES];  
    } 
} 

Nie otrzymuję żadnego błędu. Moim problemem jest wynik scalenia, to faktycznie połączenie zarządzanych obiektów z obu kontekstów.

Mój podmiot to naprawdę prosta lista atrybutów i relacji.

Być może scalenie wymaga pewnych instrukcji, aby zrozumieć, kiedy zaktualizowany obiekt zarządzany NIE JEST nowy, ale jest edytowaną wersją pierwszego. Wyobrażam sobie, że gdzieś muszę określić sposób jednoznacznego identyfikowania jednostki (atrybut może na przykład działać jak identyfikator) i coś takiego jak polityka scalania (jeśli 2 zarządzany obiekt reprezentuje ten sam obiekt, należy go pobrać z lastModificationDate nowszy).

Po prostu muszę zrozumieć, jak prawidłowo scalić 2 konteksty, aby mieć jedną zaktualizowaną kopię dla każdego obiektu.

AKTUALIZACJA 1

Problem jest teraz dla mnie jasny. Kontekst 2 ma dużą różnicę: identyfikator obiektu. Podczas gdy kontekst głównego wątku pobrał obiekt ManagedObjects z koordynatorem magazynu trwałego, drugi wątek tworzy ten obiekt, pobierając zdalny adres URL. Nawet jeśli obiekty mają tę samą zawartość, będą miały 2 różne obiektyID.

Moje obiekty miały już unikalny identyfikator, mogłem użyć setObjectId w celu ustawienia tej wartości. (Dokumentacja Apple mówi, że to NIE jest dobry pomysł).

+1

Jest oczywiste, że identyfikatory obiektów są różne, ponieważ tworzy się obiekty, a następnie pobiera je ze sklepu i aktualizuje. Właśnie dlatego powiedziałem w mojej odpowiedzi, że nie potrzeba niczego więcej, aby scalić obiekty. W każdym razie właściwym sposobem radzenia sobie z tą sytuacją jest użycie identyfikatorów zarządzanych obiektów. Ponieważ identyfikatory obiektów zarządzanych są bezpieczne dla wątków, można je przekazać z głównego wątku do innego wątku, a następnie użyć obiektu existingObjectWithID: error: do pobrania obiektu powiązanego z określonym identyfikatorem, zaktualizowania go i zapisania kontekstu. Teraz połączenie będzie działać zgodnie z oczekiwaniami. –

+0

Alternatywnie, jeśli nie wiesz z góry, jakie zarządzane identyfikatory obiektów muszą być przekazywane między wątkami, to w drugim wątku po prostu pobierasz obiekty za pomocą predykatu, aby pobrać te odpowiadające obiektom pobranym z serwera, a następnie aktualizujesz je i zapisz kontekst. –

+0

Prawidłowo! Problem stanowiły obiekty id. Teraz za każdym razem, gdy wykonuję pobieranie i muszę zaktualizować istniejący obiekt, pobieram obiekt ze sklepu i aktualizuję go. – Giuseppe

Odpowiedz

32

Oto, co należy zrobić, aby poprawnie scalić konteksty. Po pierwsze, nie potrzebujesz własnego powiadomienia.Wykonywanie operacji zapisu w kontekście automatycznie przekazuje następujące zawiadomienie dla zarejestrowanych obserwatorów:

NSManagedObjectContextDidSaveNotification 

Dlatego, wszystko co musisz zrobić, to:

1) w głównym wątku, mogą być w sposób viewDidLoad, zgłosić się do tego zgłoszenia:

[[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(contextDidSave:) 
              name:NSManagedObjectContextDidSaveNotification 
              object:nil]; 

2) wdrożenie metody contextDidSave: w głównym wątku w następujący sposób:

- (void)contextDidSave:(NSNotification *)notification 
{ 

    SEL selector = @selector(mergeChangesFromContextDidSaveNotification:); 
    [managedObjectContext performSelectorOnMainThread:selector withObject:notification waitUntilDone:YES]; 

} 

3) w metodzie dealloc dodać następujące:

[[NSNotificationCenter defaultCenter] removeObserver:self]; 

4) utworzyć nowy kontekst w innym wątku przy użyciu coś jak następującej metody:

- (NSManagedObjectContext*)createNewManagedObjectContext 
{ 

    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init]; 
    [moc setPersistentStoreCoordinator:[self persistentStoreCoordinator]]; 
    [moc setUndoManager:nil]; 
    return [moc autorelease]; 
} 

5) Po otrzymaniu nowe dane, właściwym sposobem radzenia sobie z tą sytuacją jest użycie zarządzanych identyfikatorów obiektów. Ponieważ identyfikatory obiektów zarządzanych są bezpieczne dla wątków, można je przekazać z głównego wątku do innego wątku, a następnie użyć obiektu existingObjectWithID:error: w celu pobrania obiektu powiązanego z określonym identyfikatorem, zaktualizowania go i zapisania kontekstu. Teraz połączenie będzie działać zgodnie z oczekiwaniami. Ewentualnie, jeśli nie wiesz wcześniej, jakie identyfikatory obiektów zarządzanych muszą być przekazywane między wątkami, to w drugim wątku po prostu pobierasz obiekty za pomocą predykatu w celu pobrania tych, które odpowiadają obiektom pobranym z serwera, a następnie aktualizujesz je i zapisać kontekst.

+0

To zupełnie to samo z mojej implementacji. Moim problemem jest scalenie. Po wywołaniu [self.managedObjectContext mergeChangesFromContextDidSaveNotification: saveNotification]; To powinno scalić moje ManagedObjects, ale to po prostu zrobić concatenation. – Giuseppe

+1

Trudno powiedzieć, co jest nie tak z twoją implementacją, nie widząc całego odpowiedniego kodu źródłowego. Czy na pewno zapisujesz dane w kontekście innego wątku? Zapisywanie jest wymagane (ponieważ operacja scalania porównuje obiekty w pamięci z obiektami), ale nie wspomniałeś o tym w swoim pytaniu. Informacje o scalaniu zasad. na pewno możesz ustawić jeden na każdym kontekście, jeśli domyślny nie pasuje do twoich potrzeb. Ponownie, bez dodatkowych szczegółów, trudno powiedzieć. –

+0

Ta odpowiedź jest jedynym właściwym wyjaśnieniem znalezionym w Internecie. –

Powiązane problemy