Muszę utworzyć NSManagedObject
instancje, zrobić z nimi kilka rzeczy, a następnie wyrzucić je do kosza lub przechowywać w sqlite db. Problem polega na tym, że nie mogę tworzyć instancji NSManagedObject
niepołączonych z, NSManagedObjectContext
co oznacza, że muszę jakoś wyczyścić, gdy zdecyduję, że nie potrzebuję niektórych obiektów w mojej bazie danych.
Aby sobie z tym poradzić, utworzyłem magazyn w pamięci za pomocą tego samego koordynatora i umieszczam tam tymczasowe obiekty za pomocą assignObject:toPersistentStore.
Now, jak mam się upewnić, że te tymczasowe obiekty nie dotrą do danych, które pobieram z wspólny dla kontekstu obu sklepów? A może muszę tworzyć osobne konteksty dla takiego zadania?
UPD:
Teraz myślę o stworzeniu osobnego kontekstu dla magazynu w pamięci. Jak przenosić obiekty z jednego kontekstu do drugiego? Używasz tylko [kontekstu insertObject:]? Czy to zadziała w tej konfiguracji? Jeśli wstawię jeden obiekt z wykresu obiektów, czy cały wykres również zostanie wstawiony w kontekst?
źródło
Odpowiedzi:
UWAGA: Ta odpowiedź jest bardzo stara. Zobacz komentarze do pełnej historii. Od tego czasu moje zalecenie uległo zmianie i nie zalecam już używania niepowiązanych
NSManagedObject
instancji. Obecnie zalecam używanie tymczasowychNSManagedObjectContext
instancji podrzędnych .Oryginalna odpowiedź
Najłatwiej to zrobić, tworząc
NSManagedObject
instancje bez powiązanego plikuNSManagedObjectContext
.NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC]; NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
Następnie, gdy chcesz go zapisać:
[myMOC insertObject:unassociatedObject]; NSError *error = nil; if (![myMoc save:&error]) { //Respond to the error }
źródło
iOS5 zapewnia prostszą alternatywę dla odpowiedzi Mike'a Wellera. Zamiast tego użyj podrzędnego NSManagedObjectContext. Eliminuje potrzebę korzystania z trampoliny przez NSNotificationCenter
Aby utworzyć kontekst potomny:
NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; childContext.parentContext = myMangedObjectContext;
Następnie utwórz obiekty, używając kontekstu potomnego:
NSManagedObject *o = [NSEntityDescription insertNewObjectForEntityForName:@"MyObject" inManagedObjectContext:childContext];
Zmiany są stosowane tylko po zapisaniu kontekstu potomnego. Aby odrzucić zmiany, po prostu nie zapisuj.
Nadal istnieje ograniczenie dotyczące relacji. tj. nie możesz tworzyć relacji z obiektami w innych kontekstach. Aby obejść ten problem, użyj objectID, aby pobrać obiekt z kontekstu potomnego. na przykład.
NSManagedObjectID *mid = [myManagedObject objectID]; MyManagedObject *mySafeManagedObject = [childContext objectWithID:mid]; object.relationship=mySafeManagedObject;
Uwaga, zapisanie kontekstu podrzędnego powoduje zastosowanie zmian w kontekście nadrzędnym. Zapisanie kontekstu nadrzędnego utrwala zmiany.
Pełne wyjaśnienie można znaleźć w sesji 214 wwdc 2012 .
źródło
moc
w trzecim fragmencie? Czy to jestchildContext
czymyMangedObjectContext
?NSManagedObject
już zapewnia odpowiednieNSManagedObjectContext
, możesz zautomatyzować wybór kontekstu:NSManagedObject* objectRelatedContextually = [objectWithRelationship.managedObjectContext objectWithID:objectRelated.objectID];
a następnieobjectWithRelationship.relationship = objectRelatedContextually;
.Prawidłowym sposobem osiągnięcia tego typu rzeczy jest użycie nowego kontekstu obiektu zarządzanego. Tworzysz kontekst obiektu zarządzanego z tym samym magazynem trwałym:
NSManagedObjectContext *tempContext = [[[NSManagedObjectContext alloc] init] autorelease]; [tempContext setPersistentStore:[originalContext persistentStore]];
Następnie dodajesz nowe obiekty, mutujesz je itp.
Kiedy przychodzi czas na zapisanie, musisz wywołać [tempContext save: ...] w tempContext i obsłużyć powiadomienie o zapisie, aby scalić to z oryginalnym kontekstem. Aby odrzucić obiekty, po prostu zwolnij ten tymczasowy kontekst i zapomnij o nim.
Kiedy więc zapiszesz kontekst tymczasowy, zmiany zostaną utrwalone w sklepie i po prostu musisz je przenieść z powrotem do głównego kontekstu:
/* Called when the temp context is saved */ - (void)tempContextSaved:(NSNotification *)notification { /* Merge the changes into the original managed object context */ [originalContext mergeChangesFromContextDidSaveNotification:notification]; } // Here's where we do the save itself // Add the notification handler [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tempContextSaved:) name:NSManagedObjectContextDidSaveNotification object:tempContext]; // Save [tempContext save:NULL]; // Remove the handler again [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:tempContext];
Jest to również sposób, w jaki należy obsługiwać wielowątkowe podstawowe operacje na danych. Jeden kontekst na wątek.
Jeśli chcesz uzyskać dostęp do istniejących obiektów z tego tymczasowego kontekstu (w celu dodania relacji itp.), Musisz użyć identyfikatora obiektu, aby uzyskać nową instancję, taką jak ta:
NSManagedObject *objectInOriginalContext = ...; NSManagedObject *objectInTemporaryContext = [tempContext objectWithID:[objectInOriginalContext objectID]];
Jeśli spróbujesz użyć
NSManagedObject
w złym kontekście, podczas zapisywania wystąpią wyjątki.źródło
NSManagedObjectContext
jest kosztowne zarówno pod względem pamięci, jak i procesora. Zdaję sobie sprawę, że pierwotnie było to w niektórych przykładach Apple, ale zaktualizowali i poprawili te przykłady.Tworzenie obiektów tymczasowych z kontekstu zerowego działa dobrze, dopóki nie spróbujesz stworzyć związku z obiektem, którego kontekst! = Nil!
upewnij się, że zgadzasz się z tym.
źródło
To, co opisujesz, jest dokładnie tym, do czego
NSManagedObjectContext
służy.Z przewodnika programowania podstawowych danych: Podstawowe informacje o danych
Oraz przewodnik programowania podstawowych danych: walidacja zarządzanych obiektów
NSManagedObjectContext
są zaprojektowane tak, aby były lekkie. Możesz je tworzyć i odrzucać w dowolnym momencie - to stały koordynator sklepów i jego zależności są „ciężkie”. Z jednym stałym koordynatorem magazynu może być skojarzonych wiele kontekstów. W starszym, przestarzałym modelu ograniczania wątków oznaczałoby to ustawienie tego samego stałego koordynatora magazynu w każdym kontekście. Dziś oznaczałoby to połączenie zagnieżdżonych kontekstów z kontekstem głównym, który jest powiązany z trwałym koordynatorem magazynu.Utwórz kontekst, utwórz i zmodyfikuj obiekty zarządzane w tym kontekście. Jeśli chcesz je utrwalić i zakomunikować te zmiany, zapisz kontekst. W przeciwnym razie odrzuć.
Próba stworzenia zarządzanych obiektów niezależnie od tego
NSManagedObjectContext
jest prowokacją kłopotów. Pamiętaj, że dane podstawowe to ostatecznie mechanizm śledzenia zmian dla wykresu obiektowego. Z tego powodu obiekty zarządzane są w rzeczywistości częścią kontekstu obiektu zarządzanego . Kontekst obserwuje ich cykl życia , a bez kontekstu nie wszystkie funkcje zarządzanego obiektu będą działać poprawnie.źródło
W zależności od tego, jak korzystasz z tymczasowego obiektu, istnieją pewne zastrzeżenia dotyczące powyższych zaleceń. Mój przypadek użycia polega na tym, że chcę utworzyć obiekt tymczasowy i powiązać go z widokami. Gdy użytkownik zdecyduje się zapisać ten obiekt, chcę ustawić relacje z istniejącymi obiektami i zapisać. Chcę to zrobić, aby uniknąć tworzenia tymczasowego obiektu do przechowywania tych wartości. (Tak, mógłbym po prostu poczekać, aż użytkownik zapisze, a następnie pobrać zawartość widoku, ale umieszczam te widoki wewnątrz tabeli, a logika, aby to zrobić, jest mniej elegancka).
Opcje dla obiektów tymczasowych to:
1) (Preferowane) Utwórz obiekt tymczasowy w kontekście podrzędnym. To nie zadziała, ponieważ wiążę obiekt z interfejsem użytkownika i nie mogę zagwarantować, że metody dostępu do obiektów zostaną wywołane w kontekście podrzędnym. (Nie znalazłem dokumentacji, która mówi inaczej, więc muszę założyć.)
2) Utwórz obiekt tymczasowy bez kontekstu obiektu. To nie działa i powoduje utratę / uszkodzenie danych.
Moje rozwiązanie: rozwiązałem to, tworząc tymczasowy obiekt z zerowym kontekstem obiektu, ale kiedy zapisuję obiekt, zamiast wstawiać go jako nr 2, kopiuję wszystkie jego atrybuty do nowego obiektu, który tworzę w głównym kontekście. Utworzyłem metodę pomocniczą w mojej podklasie NSManagedObject o nazwie cloneInto: która pozwala mi łatwo kopiować atrybuty i relacje dla dowolnego obiektu.
źródło
Dla mnie odpowiedź Marcusa nie zadziałała. Oto, co zadziałało dla mnie:
NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC]; NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
wtedy, jeśli zdecyduję się go zapisać:
[myMOC insertObject:unassociatedObjet]; NSError *error = nil; [myMoc save:&error]; //Check the error!
Nie możemy też zapomnieć o jej wydaniu
źródło
Przepisuję tę odpowiedź dla Swifta, tak jak wszystkie podobne pytania do szybkiego przekierowania na to pytanie.
Możesz zadeklarować obiekt bez ManagedContext przy użyciu następującego kodu.
let entity = NSEntityDescription.entity(forEntityName: "EntityName", in: myContext) let unassociatedObject = NSManagedObject.init(entity: entity!, insertInto: nil)
Później, aby zapisać obiekt, możesz wstawić go do kontekstu i zapisać.
myContext.insert(unassociatedObject) // Saving the object do { try self.stack.saveContext() } catch { print("save unsuccessful") } }
źródło