2010-01-26 14 views
55

Próbuję użyć danych podstawowych w sposób wielowątkowy. Po prostu chcę pokazać aplikację z poprzednio pobranymi danymi podczas pobierania nowych danych w tle. To powinno umożliwić użytkownikowi dostęp do aplikacji podczas procesu aktualizacji.Aplikacja wielowątkowa danych Core Data

Mam NSURLConnection, który pobiera plik asynchronicznie za pomocą delegata (i pokazujący postęp), a następnie używam XMLParser do parsowania nowych danych i tworzenia nowych obiektów NSManagedObjects w oddzielnym kontekście, z własnym magazynem persistentStore i użyciem osobnego wątku .

Problem polega na tym, że tworzenie nowych obiektów w tym samym kontekście starego, podczas wyświetlania go, może spowodować zgłoszenie wyjątku BAD_INSTRUCTION. Postanowiłem więc użyć osobnego kontekstu dla nowych danych, ale nie mogę znaleźć sposobu na przeniesienie wszystkich obiektów do innego kontekstu po zakończeniu.

Paolo aka SlowTree

Odpowiedz

138

The Apple Concurrency with Core Data documentation jest miejscem, aby rozpocząć. Przeczytaj to bardzo uważnie ... Byłem wielokrotnie ugryziony przez moje nieporozumienia!

Podstawowe zasady to:

  1. Użyj jednej NSPersistentStoreCoordinator za program. Nie potrzebujesz ich w każdym wątku.
  2. Utwórz jeden numer NSManagedObjectContext.
  3. Nigdy nie należy przekazywać NSManagedObject na wątku do innego wątku.
  4. Zamiast tego uzyskaj identyfikator obiektu za pomocą -objectID i przekaż go do innego wątku.

więcej reguł:

  1. upewnij się zapisać obiekt do sklepu, zanim się identyfikator obiektu. Do momentu zapisania są tymczasowe i nie można uzyskać do nich dostępu z innego wątku.
  2. Uważaj na zasady scalania, jeśli zmieniasz zarządzane obiekty z więcej niż jednego wątku. Pomocne jest
  3. NSManagedObjectContext z -mergeChangesFromContextDidSaveNotification:.

Ale pozwól mi powtórzyć, przeczytaj uważnie dokument! Naprawdę warto!

+1

znalazłem świetny przykład łączenia kontekstów w CoreDataBooks (mergeChangesFromContextDidSaveNotification). Dziękuję bardzo. Miłego dnia. Paolo aka SlowTree – SlowTree

+0

O, dzięki Bogu. Czytanie tego rozwiązało moje problemy. Importował duży zestaw danych w wątku tła i uzyskiwał wiele nieprzewidywalnych wyjątków. Tworzenie instancji kontekstu w wątku tła, a nie przekazywanie go, ale wydaje się, że naprawiłem moje issy. – tobyc

+2

Ten dokument nie został jeszcze zaktualizowany, aby skorzystać z bardzo ważnych ulepszeń w iOS 5 - wideo, do którego linkuję w mojej odpowiedzi jest teraz lepszym odnośnikiem. – JosephH

2

Mam nadzieję, że pomoże to wszystkim ludziom, którzy napotykają problemy przy użyciu podstawowych danych w środowisku wielowątkowym.

Spójrz na "Najlepsze utwory 2" w dokumentacji Apple. Z tym kodem wziąłem "czerwoną pigułkę" Matrixa i odkryłem nowy świat bez podwójnego wolnego błędu i bez błędów. : D

Mam nadzieję, że to pomoże.

Paolo

p.s. Wielkie dzięki dla Yuji, w dokumentacji opisanej powyżej znalazłem ten przykład.

73

Obecnie [maj 2015] numer Apple Concurrency with Core Data documentation jest w najlepszym przypadku bardzo mylący, ponieważ nie obejmuje żadnych ulepszeń w systemie iOS 5, a tym samym nie pokazuje już najlepszych sposobów jednoczesnego korzystania z danych podstawowych.Istnieją dwie bardzo ważne zmiany w systemie iOS 5 - konteksty nadrzędne i nowe typy współbieżności/wątków.

Nie znalazłem jeszcze żadnej pisemnej dokumentacji, która kompleksowo obejmuje te nowe funkcje, ale WWDC 2012 video "Session 214 - Core Data Best Practices" wyjaśnia to wszystko bardzo dobrze.

Magical Record wykorzystuje te nowe funkcje i może być warte obejrzenia.

Prawdziwe podstawy wciąż są takie same - nadal można używać tylko zarządzanych obiektów, w których wątek został utworzony w kontekście zarządzanego obiektu.

Możesz teraz użyć [moc performBlock:], aby uruchomić kod na prawym wątku.

Nie ma potrzeby używania funkcji mergeChangesFromContextDidSaveNotification: anymore; zamiast tego utwórz kontekst podrzędny, aby wprowadzić zmiany, a następnie zapisz kontekst podrzędny. Zapisanie kontekstu podrzędnego spowoduje automatyczne przesunięcie zmian do kontekstu nadrzędnego, a zapisanie zmian na dysku spowoduje wykonanie zapisu w kontekście nadrzędnym w wątku.

Aby to zadziałało musisz utworzyć kontekst nadrzędny przy jednoczesnym typu, np:

mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 

Następnie w wątku tła:

context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType]; 
[context setParentContext:mainManagedObjectContext]; 

<... perform actions on context ...> 

NSError *error; 
if (![context save:&error]) 
{ 
    <... handle error ...> 
} 
[mainManagedObjectContext performBlock:^{ 
    NSError *e = nil; 
    if (![mainContext save:&e]) 
    { 
     <... handle error ...> 
    } 
}]; 
+0

Link do WWDC wydaje się być nieprawidłowy. – Philip007

+7

Awans na szczyt -aktualne informacje. W związku z tym powinien wdrożyć mechanizm promowania odpowiedzi związanych z rozwojem nowych technologii i bagatelizować te przestarzałe akceptowane odpowiedzi. Dziękujemy za rekomendowanie frameworku Magic Record. Jego dokumentacja wygląda naprawdę ładnie. Mogę spróbować później. – Philip007

+0

W przeciwieństwie do fragmentu kodu, obiekt UIManagedDocument domyślnie tworzy jego kontekst nadrzędny w kolejce prywatnej, a kontekst podrzędny w głównej kolejce. Masz pomysł, dlaczego Apple tak robi? Czy to jest całkowicie arbitralne? – Philip007

Powiązane problemy