2016-03-01 13 views
8

Korzystam z kontekstu obiektu zarządzanego prywatnie, aby utworzyć nowe obiekty w magazynie trwałym, a następnie po zapisaniu prywatnego MOC, łącząc je z głównym MOC przy użyciu mergeChangesFromContextDidSaveNotification. To działa dobrze i aktualizuje interfejs użytkownika zgodnie z wymaganiami, a NSManagedObjectContextWillSaveNotification NIE jest tutaj wywoływany dla mainMOC.Jak ignorować zmiany w mergeChangesFromContextDidSaveNotification w NSManagedObjectContextWillSaveNotification

Następnie dokonuję pewnych zmian w mainMOC za pomocą interfejsu użytkownika i słucham NSManagedObjectContextWillSaveNotification. Powiadomienie zostało wysłane, ale zawiera nie tylko wprowadzone przeze mnie zmiany, ale także obiekty, które zostały scalone z PrivateMOC przy użyciu mergeChangesFromContextDidSaveNotification.

Czy można zignorować zmiany, które zostały scalone z innego kontekstu do mainContext, w kolejnych powiadomieniach contextDidChange?

Oto konfiguracja:

- (void) loadData { 
    privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType]; 

    privateContext.persistentStoreCoordinator = self.mainContext.persistentStoreCoordinator; 

    [[NSNotificationCenter defaultCenter] addObserver:self 
             selector:@selector(contextWillSave:) 
              name:NSManagedObjectContextWillSaveNotification 
              object: self.mainContext]; 

    NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:record.recordType inManagedObjectContext: self.privateContext]; 

    // fill in object 

    if ([self.privateContext hasChanges]) { 
     [self savePrivateContextAndMergeWithMainContext: self.privateContext]; 
    } 
} 

- (void) savePrivateContextAndMergeWithMainContext: (NSManagedObjectContext *) privateContext { 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(privateContextDidChange:) name:NSManagedObjectContextDidSaveNotification object:privateContext]; 
    __block NSError *error = nil; 
    [privateContext performBlockAndWait:^{ 
     NSLog(@"PrivateContext saved"); 
     [privateContext save:&error]; 
    }]; 


    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:privateContext]; 

    if (error) { 
     NSLog(@"error = %@", error); 
    } 
} 

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

    [self.mainContext performBlockAndWait:^{ 
     NSLog(@"merged into mainContext"); 
     [self.mainContext mergeChangesFromContextDidSaveNotification:notification]; 
    }]; 
} 

To działa prawidłowo i zapisując prywatny kontekst i wtopienie się w mainContext nie wywołać contextWillSave powiadomienie. Ale podczas edycji danych z interfejsu użytkownika (na głównym MOC) wyzwala powiadomienie i zawiera dane, które zostały wcześniej zapisane przy użyciu prywatnego MOC.

Mam nadzieję, że jest jasne. Daj mi znać, czy powinienem podać cokolwiek innego.

- AKTUALIZACJA -

Wydaje się, że problem jest ze specjalnie usuwanie obiektów z prywatnej kontekście. Po usunięciu z prywatnego kontekstu i wywołaniu mergeChangesFromContextDidSaveNotification w głównym MOC, zestaw MainMoc deletedObjects nadal pokazuje obiekt, który został usunięty. Nie dzieje się tak z wstawkami lub aktualizacjami w kontekście prywatnym. Czy to jest udokumentowane w dowolnym miejscu? Jakie może być obejście tego problemu?

+0

Dlaczego obserwujesz także główny kontekst? Co robisz z tymi zmianami? – Wain

+0

Głównym obserwatorem kontekstu jest nasłuchiwanie zmian wprowadzonych przez interfejs użytkownika, aby mogły być przekazywane do serwera. Dlatego nie chcę, aby zmiany wprowadzone w prywatnym kontekście pojawiały się w głównym słuchaczu kontekstu. Nie są początkowo, gdy zmiany są scalane z głównym kontekstem, ale wygląda na to, że MOC nadal zaznacza je jako "zmienione", a następnym razem, gdy zapiszesz główny kontekst, pojawią się one w obiekcie powiadomienia. –

+0

W rzeczywistości problem wydaje się być bardziej związany z obiektami * usuniętymi * w kontekście tła, a nie wstawionymi. Te problemy powodują ten problem, ponieważ zdają się kręcić po "mergeChangesFromContextDidSaveNotification:' nazywają się –

Odpowiedz

1

Core Data istnieje już od wielu lat i przez ten czas ewoluował model współbieżności.

Modele współbieżności "zamknięcia nici" i "blokowania" wykorzystywały powiadomienia do komunikowania zmian między kontekstami. Po zapisaniu kontekstu zostanie wysłane powiadomienie z informacją o zmianach. Informacje te można wykorzystać do scalenia zmian z jednego kontekstu do innych. To nigdy nie było szczególnie dobre i często było głównym problemem w aplikacjach. Modele "blokowania" i "uwięzienia nici" są już od wielu lat przestarzałe.

Po wprowadzeniu "ograniczenia kabinowego" wraz z nim wprowadzono pojęcie "kontekstów zagnieżdżonych". Kontekst może mieć kontekst nadrzędny, a po zapisaniu kontekstu podrzędnego zmiany te są automatycznie przekazywane do rodzica (i nie dalej). Jest to zalecany sposób komunikowania zmian między kontekstami podczas korzystania z ograniczenia kolejkowania, którym jesteś.

Nie zaleca się używania mergeChangesFromContextDidSaveNotification: z kontekstem NSPrivateQueueConcurrencyType.

Dane podstawowe wykonują wiele wewnętrznych czynności księgowych i śledzenia zmian w Twoim imieniu. Zwykle podczas operacji składowania informacje są agregowane i łączone - jest to część operacji processPendingChanges. Kiedy operacja składowania jest wykonywana wewnątrz performBlockAndWait:, może się to nie zdarzyć lub może nie być kompletna - co powoduje, że zmiany (i wszelkie powiadomienia o zmianach) są niekompletne lub wcale się nie kończą.performBlockAndWait: jest powtórką, która nie jest zgodna z procesem processPendingChanges. Użycie wartości performBlock: spowoduje bardziej spójne zachowanie.

Jeśli używasz kontekstów zagnieżdżonych do przekazywania zmian, a nie powiadomień, Twój problem zostanie rozwiązany, jak opisałeś w swoim pytaniu.

+0

"Nie zaleca się używania funkcji mergeChangesFromContextDidSaveNotification: z kontekstem NSPrivateQueueConcurrencyType." - Czy masz jakieś odniesienia do tego? Widziałem wiele artykułów, w których stwierdzono przeciwieństwo; że chociaż konteksty rodzic-dziecko są przydatne w niektórych przypadkach, powinniśmy nadal używać "mergeChangesFromContextDidSaveNotification:" z kontekstów prywatnych, gdy jest to właściwe. Czytałem książkę Core Data firmy Objc.io i używają one "mergeChangesFromContextDidSaveNotification" w wielu miejscach. –

2

Modyfikowanie privateContextDidChange takiego ...

- (void) privateContextDidChange: (NSNotification *) notification{ 
    if (notification.object == PrivateMOC) { 
     [self.mainContext performBlockAndWait:^{ 
      NSLog(@"merged into mainContext"); 
      [self.mainContext mergeChangesFromContextDidSaveNotification:notification]; 
     }]; 
    } 
} 

... gdzie PrivateMOC jest odniesienie do prywatnej Zarządzane Context Object?

+0

To nie pomaga w przypadku problemu. –

+0

Może nie pomóc w tym konkretnym przypadku; ale daje odpowiedź na jedną (część) pytań: "Czy istnieje sposób, aby zignorować zmiany, które zostały połączone z innego kontekstu [...]" :) –

Powiązane problemy