Jak radzić sobie z tymczasowymi instancjami NSManagedObject?
Muszę utworzyć NSManagedObject
instancje, zrobić z nimi kilka rzeczy, a następnie je zniszczyć lub zapisać do SQLite db. Problem polega na tym, że nie mogę tworzyć instancji NSManagedObject
niepowiązanych z NSManagedObjectContext
, a to oznacza, że muszę się jakoś oczyścić po tym, jak zdecyduję, że nie potrzebuję niektórych obiektów w moim db.
Aby sobie z tym poradzić, stworzyłem magazyn w pamięci przy użyciu tego samego koordynatora i umieszczam tam tymczasowe obiekty za pomocą assignObject:toPersistentStore.
Teraz, Jak mam się upewnić, że te tymczasowe obiekty nie dostaną się do dane, które pobieram ze wspólnego dla obu sklepów kontekstu? Czy muszę tworzyć osobne konteksty dla takiego zadania?
Upd:
Teraz myślę o stworzeniu osobnego kontekstu dla magazynu w pamięci. Jak przenieść obiekty z jednego kontekstu do drugiego? Po prostu za pomocą [context insertObject:]? Czy to działa OK w tej konfiguracji? Jeśli wstawiam jeden obiekt z wykresu obiektów, to czy cały wykres również zostanie wstawiony do kontekstu?8 answers
UWAGA: ta odpowiedź jest bardzo stara. Zobacz komentarze do pełnej historii. Od tego czasu moje rekomendacje uległy zmianie i nie zalecam już używania niezwiązanych instancji NSManagedObject
. Obecnie zalecam używanie tymczasowych instancji child NSManagedObjectContext
.
Oryginalna Odpowiedź
Najprostszym sposobem na to jest utworzenie instancji NSManagedObject
bez powiązanego NSManagedObjectContext
.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC];
NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
Wtedy gdy chcesz go zapisać:
[myMOC insertObject:unassociatedObject];
NSError *error = nil;
if (![myMoc save:&error]) {
//Respond to the error
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-20 18:16:23
IOS5 stanowi prostszą alternatywę dla odpowiedzi Mike ' a Wellera. Zamiast tego użyj potomka NSManagedObjectContext. Usuwa potrzebę 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 wtedy, gdy kontekst potomny jest zapisywany. Tak więc, aby odrzucić zmiany, po prostu nie zapisuj.
Nadal istnieje ograniczenie związków. ie nie można utworzyć relacje z obiektami w innych kontekstach. Aby obejść to użyj objectID ' s, aby uzyskać obiekt z kontekstu potomnego. np.
NSManagedObjectID *mid = [myManagedObject objectID];
MyManagedObject *mySafeManagedObject = [childContext objectWithID:mid];
object.relationship=mySafeManagedObject;
Uwaga, zapisanie kontekstu potomnego stosuje zmiany do kontekstu rodzica. Zapisywanie kontekstu nadrzędnego trwa nadal.
Zobacz wwdc 2012 sesja 214 aby uzyskać pełne wyjaśnienie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-07 22:19:06
Poprawnym sposobem osiągnięcia tego rodzaju rzeczy jest użycie nowego kontekstu zarządzanego obiektu. Tworzy się kontekst zarządzanego obiektu z tym samym trwałym magazynem:
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:...] na tempContext i obsłuż powiadomienie Zapisz, aby połączyć je z oryginalnym kontekstem. Aby odrzucić obiekty, po prostu zwolnij ten tymczasowy kontekst i zapomnij o nim.
Więc kiedy zapisujesz tymczasowy kontekst, zmiany są utrzymywane w sklepie i musisz tylko wprowadzić te zmiany 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 powinieneś obsługiwać wielowątkowe operacje na danych. Jeden kontekst na wątek.
Jeśli chcesz uzyskać dostęp do istniejących obiektów z tego tymczasowego kontekstu (aby dodać relacje itp.) następnie musisz użyć ID obiektu, aby uzyskać nową instancję w ten sposób:
NSManagedObject *objectInOriginalContext = ...;
NSManagedObject *objectInTemporaryContext = [tempContext objectWithID:[objectInOriginalContext objectID]];
Jeśli spróbujesz użyć NSManagedObject
w niewłaściwym kontekście podczas zapisywania otrzymasz wyjątki.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-15 14:37:32
Tworzenie obiektów tymczasowych z kontekstu zerowego działa dobrze, dopóki nie spróbujesz nawiązać relacji z obiektem, którego kontekst != zero!
Upewnij się, że zgadzasz się z tym.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-03 12:55:32
To, co opisujesz, jest dokładnie tym, do czego służy NSManagedObjectContext
.
From Core Data Programming Guide: Core Data Basics
Zarządzany kontekst obiektu można traktować jako inteligentną podkładkę pod zarysowania. Pobieranie obiektów z magazynu trwałego powoduje przeniesienie tymczasowych kopii na obszar magazynowania, w którym tworzą one Wykres obiektu (lub zbiór Wykresów obiektowych). Następnie możesz modyfikować te obiekty w dowolny sposób. Chyba, że faktycznie zapiszesz te zmiany, jednak trwały magazyn pozostaje niezmieniony.
I Przewodnik Programowania Podstawowych Danych: Zarządzana Walidacja Obiektów
Jest to również podstawą idei zarządzanego kontekstu obiektu reprezentującego "scratch pad" -ogólnie można przenieść zarządzane obiekty na scratch pad i edytować je w dowolny sposób, zanim ostatecznie zatwierdzisz zmiany lub je odrzucisz.
NSManagedObjectContext
s są zaprojektowane tak, aby były lekkie. Można je tworzyć i odrzucać do woli - jest to uporczywe sklepy i to one są "ciężkie". Pojedynczy koordynator trwałego sklepu może mieć wiele kontekstów związanych z nim. W przypadku starszego, przestarzałego modelu ograniczania wątków oznaczałoby to ustawienie tego samego koordynatora trwałego sklepu w każdym kontekście. Obecnie oznaczałoby to połączenie zagnieżdżonych kontekstów z kontekstem głównym, który jest powiązany z koordynatorem trwałego magazynu.
Tworzenie kontekstu, tworzenie i modyfikowanie zarządzanych obiektów w tym kontekście. Jeśli chcesz je utrzymywać i komunikować te zmiany, Zapisz kontekst. W przeciwnym razie należy go wyrzucić.
Próba utworzenia zarządzanych obiektów niezależnie od NSManagedObjectContext
wymaga kłopotów. Pamiętaj, że podstawowe dane są ostatecznie mechanizmem śledzenia zmian dla wykresu obiektowego. Z tego powodu zarządzane obiekty są w rzeczywistości częścią kontekstu zarządzanych obiektów . Kontekst obserwuje ich cykl życia i bez kontekstu nie wszystkie funkcje zarządzanych obiektów będą działaj poprawnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-15 10:44:04
W zależności od zastosowania obiektu tymczasowego istnieją pewne zastrzeżenia do 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, mogę po prostu poczekać, aż użytkownik zapisze, a następnie pobrać zawartość widoku, ale umieszczam te widoki wewnątrz tabeli i logika jest mniej elegancka.)
Opcje dla obiektów tymczasowych to:
1) (preferowane) tworzy obiekt tymczasowy w kontekście potomnym. To nie zadziała, ponieważ wiążę obiekt z interfejsem użytkownika i nie mogę zagwarantować, że Accesory do obiektów są wywoływane w kontekście potomnym. (Nie znalazłem żadnej dokumentacji, która stanowi inaczej, więc muszę założyć.)
2) Utwórz obiekt tymczasowy z zerowym kontekstem obiektu. To nie działa i skutkuje danymi strata/korupcja.
Moje Rozwiązanie: Rozwiązałem to tworząc tymczasowy obiekt z zerowym kontekstem obiektu, ale kiedy zapisuję obiekt, zamiast wstawiać go jako #2, kopiuję wszystkie jego atrybuty do nowego obiektu, który tworzę w głównym kontekście. Stworzyłem w mojej podklasie nsmanagedobject metodę wspierającą cloneInto: która pozwala mi łatwo kopiować atrybuty i relacje dla dowolnego obiektu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-09 19:08:41
Dla mnie odpowiedź Marcusa nie zadziałała. Oto co mi się udało:
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
[unassociatedObject release]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-28 09:49:09
Przepisuję tę odpowiedź dla Swifta, tak jak wszystkie podobne pytania dla Swifta Przekierowuję na to pytanie.
Możesz zadeklarować obiekt bez ManagedContext używając poniższego 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")
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-17 10:49:52