Есть ли способ создать экземпляр объекта NSManagedObject без его вставки?
У меня есть пользовательский интерфейс для вставки транзакции. как только пользователь нажимает на плюс, он получает экран, и я хочу создать экземпляр объекта Core Data NSManagedObject, чтобы пользователь мог работать над ним. Затем, когда пользователь нажимает кнопку "Сохранить", я вызываю функцию сохранения.
поэтому до кода:
transaction = (Transaction *)[NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:self.managedObjectContext];
//even if i dont call save: its going to show up on my table
[self.managedObjectContext save:&error]
P.S Я использую NSFetchedResultsController в этой таблице, и я вижу, что NSFetchedResultsController вставляет раздел и объект в таблицу.
Моя мысль заключается в том, что есть способ создать экземпляр транзакции NSManagedObject, я мог бы обновить его с сохранением до тех пор, пока клиент не перейдет к.
Ответы
Ответ 1
Существует фундаментальная проблема с использованием nil MOC: объекты в разных MOC не должны ссылаться друг на друга — это, по-видимому, также применяется, когда одна сторона отношения имеет нулевой MOC. Что произойдет, если вы сохраните? (Что происходит, когда сохраняется другая часть вашего приложения?)
Если у вашего объекта нет отношений, то есть много вещей, которые вы можете сделать (например, NSCoding).
Возможно, вы сможете использовать -[NSManagedObject isInserted]
в NSPredicate (предположительно это ДА между вставкой и успешной сохранностью). В качестве альтернативы вы можете использовать свойство переходного процесса с тем же поведением (установите его в YES в awakeFromInsert и NO в willSave). Обе эти проблемы могут быть проблематичными, если сохраняется другая часть вашего приложения.
Использование второго MOC - это то, что, как предполагается, используется CoreData; он автоматически обрабатывает обнаружение и разрешение конфликтов. Конечно, вы не хотите создавать новый MOC каждый раз, когда есть изменения; может быть смутно иметь один MOC для несохраненных изменений медленным "пользовательским потоком", если вы не возражаете, чтобы некоторые части пользовательского интерфейса видели несохраненные изменения в других частях (накладные расходы на связь между MOC незначительны).
Ответ 2
За что стоит, Маркус Зарра, похоже, продвигает контекстный подход nil
, утверждая, что это дорого для создания нового контекста. Для получения дополнительной информации см. этот ответ к аналогичному вопросу.
Обновление
В настоящее время я использую подход с контекстом nil и столкнулся с чем-то, что может представлять интерес для других. Чтобы создать управляемый объект без контекста, вы используете метод initWithEntity:insertIntoManagedObjectContext:
NSManagedObject
. Согласно документации Apple для этого метода:
Если context
не nil
, этот метод вызывает [context insertObject:self]
(что приводит к тому, что awakeFromInsert
вызывается).
Значение здесь важно. Использование контекста nil
при создании управляемого объекта предотвратит вызов insertObject:
и, следовательно, предотвратит вызов awakeFromInsert
. Следовательно, любая инициализация объекта или установка значений свойств по умолчанию, выполненных в awakeFromInsert
, не будут выполняться автоматически при использовании контекста nil
.
Нижняя строка: при использовании управляемого объекта без контекста awakeFromInsert
не будет вызываться автоматически, и вам может потребоваться дополнительный код для компенсации.
Ответ 3
вот как я это обработал:
При загрузке, где мы знаем, что имеем дело с новой транзакцией, я создал вне контекста один.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Transaction" inManagedObjectContext:self.managedObjectContext];
transaction = (Transaction *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
тогда, когда дело дошло до установления отношения, я сделал это:
if( transaction.managedObjectContext == nil){
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:self.managedObjectContext];
Category *category = (Category *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
category.title = ((Category *)obj).title;
transaction.category = category;
[category release];
}
else {
transaction.category = (Category *)obj;
}
и в конце для сохранения:
if (transaction.managedObjectContext == nil) {
[self.managedObjectContext insertObject:transaction.category];
[self.managedObjectContext insertObject:transaction];
}
//NSLog(@"\n saving transaction\n%@", self.transaction);
NSError *error;
if (![self.managedObjectContext save:&error]) {
// Update to handle the error appropriately.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1); // Fail
}
Ответ 4
Вы можете вставить NSManagedObjectContext
с помощью -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:]
, передав nil
для контекста управляемого объекта. Разумеется, вы должны назначить его контексту (используя -[NSManageObjectContext insertObject:]
перед сохранением. Это, насколько мне известно, не является действительно намеченным шаблоном в Core Data, однако (но см. @mzarra answer здесь). Существуют некоторые сложные проблемы с упорядочением (т.е. убедиться, что экземпляр присваивается контексту, прежде чем он ожидает его наличия и т.д.). Более стандартный шаблон - создать новый управляемый объект контекст и вставьте новый объект в этот контекст. Когда пользователь сохраняет, сохраняет контекст и обрабатывает NSManagedObjectDidSaveNotification
, чтобы объединить изменения в ваш "основной" контекст. Если пользователь отменяет транзакцию, вы просто сбрасываете контекст и продолжайте свой бизнес.
Ответ 5
NSManagedObject может быть создан с использованием nil в качестве контекста, но если другие NSManagedObjects, с которыми он должен ссылаться, приведет к ошибке. Как я это делаю, я передаю контекст на экран назначения и создаю NSManagedObject на этом экране. Внесите все изменения в другие NSManagedObjects. Если пользователь удаляет кнопку отмены, я удаляю NSManagedObject и сохраняю контекст. Если пользователь удаляет кнопку сохранения, я обновляю данные в NSManagedObject, сохраняю его в контексте и отпускаю на экране. На исходном экране я обновляю таблицу с помощью перезагрузки.
Удаление NSManagedObject на целевом экране дает ключевое время для обновления файла. Обычно вам достаточно времени, чтобы вы не увидели изменения в таблице. В приложении iPhone Calendar у вас есть задержка с момента его сохранения до времени, отображаемого в виде таблицы. Это можно считать хорошей вещью с точки зрения пользовательского интерфейса, что ваш пользователь сосредоточится на только что добавленной строке. Надеюсь, это поможет.
Ответ 6
transaction = (Transaction *)[NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:nil];
если последний параметр равен nil, он вернет объект NSManagedObject без сохранения в db