Мне нужно создать NSManagedObject
экземпляры, сделать с ними что-то, а затем выбросить их или сохранить в sqlite db. Проблема в том, что я не могу создавать экземпляры NSManagedObject
неподключенных к, NSManagedObjectContext
а это означает, что мне нужно как-то прояснить ситуацию после того, как я решу, что мне не нужны некоторые объекты в моей базе данных.
Чтобы справиться с этим, я создал хранилище в памяти, используя тот же координатор, и я помещаю туда временные объекты с помощью assignObject:toPersistentStore.
Теперь, как мне убедиться, что эти временные объекты не попадают в данные, которые я получаю из общий для обоих магазинов контекст? Или мне нужно создавать отдельные контексты для такой задачи?
UPD:
Теперь я думаю о создании отдельного контекста для хранилища в памяти. Как мне перемещать объекты из одного контекста в другой? Просто используя [context insertObject:]? Будет ли нормально работать в этой настройке? Если я вставлю один объект из графа объектов, будет ли весь граф также вставлен в контекст?
Ответы:
ПРИМЕЧАНИЕ. Этот ответ очень старый. См. Комментарии для полной истории. С тех пор моя рекомендация изменилась, и я больше не рекомендую использовать несвязанные
NSManagedObject
экземпляры. Моя текущая рекомендация - использовать временные дочерниеNSManagedObjectContext
экземпляры.Оригинальный ответ
Самый простой способ сделать это - создать свои
NSManagedObject
экземпляры без связанногоNSManagedObjectContext
.NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC]; NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
Затем, когда вы захотите его сохранить:
[myMOC insertObject:unassociatedObject]; NSError *error = nil; if (![myMoc save:&error]) { //Respond to the error }
источник
iOS5 предоставляет более простую альтернативу ответу Майка Веллера. Вместо этого используйте дочерний NSManagedObjectContext. Устраняет необходимость кататься на батуте через NSNotificationCenter
Чтобы создать дочерний контекст:
NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; childContext.parentContext = myMangedObjectContext;
Затем создайте свои объекты, используя дочерний контекст:
NSManagedObject *o = [NSEntityDescription insertNewObjectForEntityForName:@"MyObject" inManagedObjectContext:childContext];
Изменения применяются только при сохранении дочернего контекста. Так что отменить изменения точно не спасают.
Есть еще ограничение на отношения. т.е. вы не можете создавать отношения с объектами в других контекстах. Чтобы обойти это, используйте objectID, чтобы получить объект из дочернего контекста. например.
NSManagedObjectID *mid = [myManagedObject objectID]; MyManagedObject *mySafeManagedObject = [childContext objectWithID:mid]; object.relationship=mySafeManagedObject;
Обратите внимание, что при сохранении дочернего контекста изменения применяются к родительскому контексту. При сохранении родительского контекста изменения сохраняются.
См. Сессию 214 на wwdc 2012 г. для полного объяснения.
источник
moc
в третьем фрагменте? ЭтоchildContext
илиmyMangedObjectContext
?NSManagedObject
уже предоставлено актуальноеNSManagedObjectContext
, вы можете автоматизировать выбор контекста:NSManagedObject* objectRelatedContextually = [objectWithRelationship.managedObjectContext objectWithID:objectRelated.objectID];
а затемobjectWithRelationship.relationship = objectRelatedContextually;
.Правильный способ добиться такого рода вещей - использовать новый контекст управляемого объекта. Вы создаете контекст управляемого объекта с тем же постоянным хранилищем:
NSManagedObjectContext *tempContext = [[[NSManagedObjectContext alloc] init] autorelease]; [tempContext setPersistentStore:[originalContext persistentStore]];
Затем вы добавляете новые объекты, изменяете их и т. Д.
Когда приходит время сохранять, вам нужно вызвать [tempContext save: ...] в tempContext и обработать уведомление о сохранении, чтобы объединить его с исходным контекстом. Чтобы отбросить объекты, просто отпустите этот временный контекст и забудьте о нем.
Поэтому, когда вы сохраняете временный контекст, изменения сохраняются в магазине, и вам просто нужно вернуть эти изменения обратно в ваш основной контекст:
/* 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];
Таким же образом следует обрабатывать многопоточные операции с данными ядра. Один контекст на поток.
Если вам нужно получить доступ к существующим объектам из этого временного контекста (для добавления отношений и т. Д.), Вам необходимо использовать идентификатор объекта, чтобы получить новый экземпляр, например:
NSManagedObject *objectInOriginalContext = ...; NSManagedObject *objectInTemporaryContext = [tempContext objectWithID:[objectInOriginalContext objectID]];
Если вы попытаетесь использовать
NSManagedObject
неправильный контекст, вы получите исключения при сохранении.источник
NSManagedObjectContext
затрат как памяти, так и процессора. Я понимаю, что изначально это было в некоторых примерах Apple, но они обновили и исправили эти примеры.Создание временных объектов из контекста nil отлично работает до тех пор, пока вы действительно не попытаетесь установить связь с объектом, контекст которого! = Nil!
убедитесь, что вы согласны с этим.
источник
То, что вы описываете, - это именно то,
NSManagedObjectContext
для чего предназначен.Из Руководства по программированию основных данных: Основы основных данных
И Руководство по программированию основных данных: проверка управляемых объектов
NSManagedObjectContext
s разработаны, чтобы быть легкими. Вы можете создавать и отбрасывать их по желанию - это постоянный координатор хранилищ, и его зависимости являются «тяжелыми». С одним постоянным координатором хранилища может быть связано множество контекстов. В более старой, устаревшей модели ограничения потоков это означало бы установку одного и того же постоянного координатора хранилища для каждого контекста. Сегодня это будет означать подключение вложенных контекстов к корневому контексту, который связан с постоянным координатором хранилища.Создавайте контекст, создавайте и изменяйте управляемые объекты в этом контексте. Если вы хотите сохранить их и сообщить об этих изменениях, сохраните контекст. В противном случае выбросьте его.
Попытка создать управляемые объекты независимо от объекта
NSManagedObjectContext
вызывает проблемы. Помните, что Core Data - это, в конечном счете, механизм отслеживания изменений для графа объектов. По этой причине управляемые объекты действительно являются частью контекста управляемого объекта . Контекст наблюдает за их жизненным циклом , и без контекста не все функции управляемого объекта будут работать правильно.источник
В зависимости от того, как вы используете временный объект, к приведенным выше рекомендациям следует делать некоторые оговорки. В моем случае я хочу создать временный объект и привязать его к представлениям. Когда пользователь решает сохранить этот объект, я хочу установить отношения с существующими объектами и сохранить. Я хочу сделать это, чтобы избежать создания временного объекта для хранения этих значений. (Да, я мог бы просто подождать, пока пользователь сохранит, а затем захватить содержимое представления, но я помещаю эти представления внутри таблицы, и логика для этого менее элегантна.)
Возможные варианты временных объектов:
1) (Предпочтительно) Создайте временный объект в дочернем контексте. Это не сработает, потому что я привязываю объект к пользовательскому интерфейсу и не могу гарантировать, что средства доступа к объекту будут вызваны в дочернем контексте. (Я не нашел никакой документации, в которой говорится об обратном, поэтому я должен предположить.)
2) Создайте временный объект с нулевым контекстом объекта. Это не работает и приводит к потере / повреждению данных.
Мое решение: я решил это, создав временный объект с нулевым контекстом объекта, но когда я сохраняю объект, а не вставляю его как № 2, я копирую все его атрибуты в новый объект, который я создаю в основном контексте. Я создал вспомогательный метод в своем подклассе NSManagedObject под названием cloneInto: он позволяет мне легко копировать атрибуты и отношения для любого объекта.
источник
Для меня ответ Маркуса не сработал. Вот что у меня сработало:
NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC]; NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
затем, если я решу его сохранить:
[myMOC insertObject:unassociatedObjet]; NSError *error = nil; [myMoc save:&error]; //Check the error!
Мы также должны не забыть выпустить его
источник
Я переписываю этот ответ для Swift, как и все похожие вопросы для быстрого перенаправления на этот вопрос.
Вы можете объявить объект без какого-либо ManagedContext, используя следующий код.
let entity = NSEntityDescription.entity(forEntityName: "EntityName", in: myContext) let unassociatedObject = NSManagedObject.init(entity: entity!, insertInto: nil)
Позже, чтобы сохранить объект, вы можете вставить его в контекст и сохранить.
myContext.insert(unassociatedObject) // Saving the object do { try self.stack.saveContext() } catch { print("save unsuccessful") } }
источник