Как бороться с временными экземплярами NSManagedObject?

Мне нужно создать экземпляры NSManagedObject, поработать с ними, а затем удалить их или сохранить в sqlite db. Проблема в том, что я не могу создать экземпляры NSManagedObject, не связанные с NSManagedObjectContext и это означает, что мне нужно как-то прояснить ситуацию после того, как я решу, что мне не нужны некоторые объекты в моей БД.

Чтобы справиться с этим, я создал хранилище в памяти, используя тот же координатор, и помещаю туда временные объекты, используя assignObject:toPersistentStore. Теперь, как мне убедиться, что эти временные объекты не попадают в данные, которые я извлекаю из общего для обоих хранилищ контекста? Или я должен создать отдельные контексты для такой задачи?


UPD:

Сейчас я думаю о создании отдельного контекста для хранилища в памяти. Как мне переместить объекты из одного контекста в другой? Просто используя [context insertObject:]? Будет ли это работать нормально в этой настройке? Если я вставлю один объект из графа объектов, весь граф также будет вставлен в контекст?

83 голоса | спросил fspirit 15 J000000Thursday10 2010, 17:56:27

8 ответов


0

ПРИМЕЧАНИЕ. Этот ответ очень старый. Смотрите комментарии для полной истории. С тех пор моя рекомендация изменилась, и я больше не рекомендую использовать несвязанные экземпляры 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
}
ответил Marcus S. Zarra 15 J000000Thursday10 2010, 22:02:08
0

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;

Обратите внимание, что при сохранении дочернего контекста изменения применяются к родительскому контексту. Сохранение родительского контекста сохраняет изменения.

См. wwdc 2012, сессия 214 для более подробного объяснения. /р>

ответил railwayparade 24 Jam1000000amThu, 24 Jan 2013 08:43:58 +040013 2013, 08:43:58
0

Правильный способ достижения такого рода вещей - с помощью нового контекста управляемого объекта. Вы создаете контекст управляемого объекта с тем же постоянным хранилищем:

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 в неверном контексте, вы получите исключения при сохранении.

ответил Mike Weller 15 J000000Thursday10 2010, 18:37:32
0

Создание временных объектов из нулевого контекста работает нормально, пока вы на самом деле не попытаетесь установить связь с объектом, контекст которого! = nil!

убедитесь, что вы в порядке с этим.

ответил user134611 3 FebruaryEurope/MoscowbFri, 03 Feb 2012 16:55:32 +0400000000pmFri, 03 Feb 2012 16:55:32 +040012 2012, 16:55:32
0

Вы описываете именно то, для чего NSManagedObjectContext.

Из Руководства по программированию основных данных: основы основных данных

  

Вы можете думать о контексте управляемого объекта как о интеллектуальном блокноте. Когда вы выбираете объекты из постоянного хранилища, вы переносите временные копии на блокнот, где они образуют граф объектов (или коллекцию графов объектов). Затем вы можете изменить эти объекты так, как вам нравится. Однако, если вы не сохраните эти изменения, постоянное хранилище останется неизменным.

И Руководство по программированию основных данных: проверка управляемых объектов

  

Это также подкрепляет идею контекста управляемого объекта, представляющего «блокнот» - обычно вы можете переносить управляемые объекты на блокнот и редактировать их по своему усмотрению, прежде чем в конечном итоге либо зафиксировать изменения, либо отказаться от них.

NSManagedObjectContext разработаны так, чтобы быть легкими. Вы можете создавать и удалять их по своему усмотрению - это постоянный координатор магазинов и его зависимости "тяжелые". С одним постоянным координатором хранилища может быть связано много контекстов. В старой устаревшей модели ограничения потока это означало бы установку одного и того же постоянного координатора хранилища в каждом контексте. Сегодня это будет означать подключение вложенных контекстов к корневому контексту, связанному с координатором постоянного хранилища.

Создайте контекст, создайте и измените управляемые объекты в этом контексте. Если вы хотите сохранить их и сообщить об этих изменениях, сохраните контекст. В противном случае откажитесь от него.

Попытка создания управляемых объектов независимо от NSManagedObjectContext вызывает проблемы. Помните, что Core Data - это механизм отслеживания изменений для графа объектов. Из-за этого управляемые объекты действительно являются часть контекста управляемого объекта . Контекст отмечает их жизненный цикл и без контекста не все функции управляемого объекта будут работать правильно.

ответил quellish 15 PM00000020000005031 2014, 14:33:50
0

В зависимости от того, как вы используете временный объект, существуют некоторые предостережения в отношении приведенных выше рекомендаций. Мой вариант использования заключается в том, что я хочу создать временный объект и связать его с представлениями. Когда пользователь решает сохранить этот объект, я хочу установить отношения с существующими объектами и сохранить. Я хочу сделать это, чтобы избежать создания временного объекта для хранения этих значений. (Да, я мог бы просто подождать, пока пользователь сохранит и затем захватить содержимое представления, но я помещаю эти представления в таблицу, и логика для этого менее элегантна.)

Опции для временных объектов:

1) (Предпочитаемый) Создайте временный объект в дочернем контексте. Это не сработает, потому что я привязываю объект к пользовательскому интерфейсу и не могу гарантировать, что средства доступа к объектам вызываются в дочернем контексте. (Я не нашел никакой документации, в которой указано иное, поэтому я должен предположить.)

2) Создайте временный объект с нулевым контекстом объекта. Это не работает и приводит к потере /повреждению данных.

Мое решение: Я решил это путем создания временного объекта с нулевым контекстом объекта, но когда я сохраняю объект, а не вставляю его как # 2, я копирую все его атрибуты в новый объект, который я создаю в основном контексте. Я создал вспомогательный метод в своем подклассе NSManagedObject под названием cloneInto: он позволяет мне легко копировать атрибуты и отношения для любого объекта.

ответил greg 9 FebruaryEurope/MoscowbMon, 09 Feb 2015 22:08:41 +0300000000pmMon, 09 Feb 2015 22:08:41 +030015 2015, 22:08:41
0

Для меня ответ Маркуса не сработал. Вот что сработало для меня:

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!

Мы также не должны забывать выпустить его

[unassociatedObject release]
ответил Lucas 28 J000000Thursday11 2011, 13:49:09
0

Я переписываю этот ответ для Swift, поскольку все похожие вопросы для 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")
    }
}
ответил Mitul Jindal 17 52017vEurope/Moscow11bEurope/MoscowFri, 17 Nov 2017 13:49:52 +0300 2017, 13:49:52

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132