2010-12-17 17 views
7

alt textPomoc z podstawowej aplikacji wielowątkowych danych projektowych

Powyżej jest uproszczeniem tego, co mój model wygląda. Moja aplikacja ma obiekt NSWindowController sterujący dwoma obiektami NSViewController dla podmiotów użytkownika. Gdy użytkownik loguje się do aplikacji, może modyfikować informacje o użytkowniku lub koncie, przywołując odpowiedni kontroler widoku. W tle mam aplikację okresowo zapełniającą logi użytkownika w delegacie aplikacji w osobnym wątku.

Używam oddzielnego NSManagedObjectContext dla wątku tła i pliku NSManagedObjectContext delegata aplikacji do wprowadzania danych w kontrolerach widoku. Chciałbym wiedzieć kilka rzeczy:

1) Czy to jest dobra praktyka? Czy należy utworzyć NSManagedObjectContext dla każdego kontrolera widoku, a następnie scalić konteksty, gdy użytkownik wprowadzi zmiany?

2) Ponieważ jednostka log jest tworzona w wątku tła, ma swoją własną NSManagedObjectContext. Jednak każdy dziennik zawiera informacje z jednostek kont użytkownik i , które są utworzone w aplikacji NSManagedObjectContext delegata aplikacji. To jak ja ściągam użytkownika:

- (NSManagedObjectID*) fetchUser:(NSString*) userID { 
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"user":inManagedObjectContext:self.managedObjectContext]; 
    /** snip **/ 
} 

Metoda ta jest wywoływana przez wątek tła w następujący sposób:

NSManagedObjectID* userObjectID = [self fetchUser:userID]; 
NSManagedObject* userObject = [self.logsManagedObjectContext objectWithID:userObjectID]; 

Czy to, co robię w fetchUser wątku bezpieczny? Czy muszę zablokować główny kontekst obiektu zarządzanego podczas pobierania użytkownika w przypadku, gdy jeden z widoków modyfikuje tego samego użytkownika? Od this article Rozumiem (być może niepoprawnie), że być może będę musiał to zrobić. Do tej pory nie napotkaliśmy żadnych problemów, ale nie chcę opuścić potencjalnego przypadku skrajnego.

3) Gdy jeden z kontrolerów widoku wprowadza zmiany do delegata aplikacji na NSManagedObjectContext to księguje powiadomienie, że jest obsługiwany w sposób następujący:

- (void)contextDidSave:(NSNotification *)notification { 
    SEL selector = @selector(mergeChangesFromContextDidSaveNotification:); 
    [self.logManagedObectContext performSelector:selector onThread:backgroundThread withObject:notification waitUntilDone:NO]; 
} 

Czy to w jaki sposób należy obsługiwać scalania lub powinien być scalenie zamiast tego delegata aplikacji NSManagedObjectContext? Odkryłem, że robienie tego (w głównym wątku) blokowało interfejs użytkownika.

Każda pomoc zostanie doceniona.

Odpowiedz

9

NSManagedObjectContext obiekty nie są bezpieczne dla wątków. Oznacza to, że jeśli chcesz uzyskać dostęp do danych podstawowych z wielu wątków, będziesz potrzebował po jednym dla każdego wątku (i utworzony również w wątku). Każdy z nich może używać tego samego NSPersistentStoreCoordinator, który serializuje dostęp do magazynu trwałego.

Dzieje się tak dlatego, że każdy NSManagedObjectContextwie jak prawidłowo zablokować NSPersistentStoreCoordinator gdy jest w użyciu, unikając kolizji. Przestrzegając tych zasad, powinieneś pozostać wątkowo bezpieczny.

Obiekty, które już robisz, powinny być używane do przekazywania obiektów Core Data z jednego MOC-a do innego (i z jednego wątku do drugiego).Jednak dzwonisz pod numer fetchUser:, który używa MOC z głównego wątku na pierwszym tle. To nie jest poprawne. To wywołanie metody fetchUser: musi zostać wywołane z głównego wątku. Oczywiście nic nie powstrzyma cię przed odzyskaniem użytkownika w wątku tła za pomocą MOC-a w tle.

Podsumowując, zawsze dzwonić do NSManagedObjectContext z wątku został utworzony w.

Sztuką jest, aby upewnić się, że oba MOCy wiedzieć o drugiej oszczędza, więc musisz się zarejestrować aby otrzymywać powiadomienia z każdy kontekst. Powinieneś wtedy wykonać mergeChangesFromContextDidSaveNotification: z odpowiedniego wątku dla MOC. W tej chwili kontekst tła jest powiadamiany o zmianach z kontekstu głównego wątku, ale nie odwrotnie.

Aha, i nie ma potrzeby oddzielnego kontekstu dla każdego NSViewController. Jako elementy interfejsu użytkownika ich interakcje z kontekstem będą odbywać się w tym samym (głównym) wątku, więc udostępnianie jest w porządku.

+0

Nie wiedziałem, że mogę po prostu odzyskać użytkownika z tła MOC. Wszystko, co muszę zrobić, to dać im ten sam ** NSPersistentStoreCoordinator **? Jeśli to zrobię, muszę pobrać przy użyciu identyfikatora obiektu lub czy mogę uzyskać obiekt bezpośrednio? – David

+0

Możesz pobrać obiekty bezpośrednio. Wystarczy napisać kod, aby scalić zmiany po otrzymaniu powiadomienia od innych MOC dzielących tego samego koordynatora. – paulbailey

Powiązane problemy