我有一个用户界面来插入一个Transaction。一旦用户点击加号,他就会获得屏幕,我想要实例化我的核心数据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我可以更新它而不保存客户选择。
答案 0 :(得分:37)
对于它的价值,Marcus Zarra似乎正在推广nil
上下文方法,声称创建新上下文的成本很高。有关详细信息,请参阅this answer以查找类似问题。
<强>更新强>
我目前正在使用nil上下文方法并遇到了其他人可能感兴趣的内容。要创建没有上下文的托管对象,请使用initWithEntity:insertIntoManagedObjectContext:
NSManagedObject
方法。根据Apple关于此方法的文档:
如果
context
不是nil
,则此方法 调用[context insertObject:self]
(导致awakeFromInsert
调用)。
这里的含义很重要。在创建托管对象时使用nil
上下文将阻止调用insertObject:
,从而阻止调用awakeFromInsert
。因此,使用awakeFromInsert
上下文时,nil
中完成的任何对象初始化或默认属性值的设置都不会自动发生。
结论:当使用没有上下文的托管对象时,将不会自动调用awakeFromInsert
,您可能需要额外的代码来补偿。
答案 1 :(得分:19)
这是我如何解决的问题:
在加载时,我们知道我们正在处理一个新事务,我创建了一个脱离上下文的。
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
}
答案 2 :(得分:17)
使用零MOC存在一个基本问题:不同MOC中的对象不应该互相引用 - 这可能也适用于关系的一方没有MOC的情况。如果你保存会怎么样? (当您的应用的另一部分保存时会发生什么?)
如果你的对象没有关系,那么你可以做很多事情(比如NSCoding)。
您可以在NSPredicate中使用-[NSManagedObject isInserted]
(可能在插入和成功保存之间是“是”)。或者,您可以使用具有相同行为的瞬态属性(在awakeFromInsert中将其设置为YES,在willSave中将其设置为NO)。如果您的应用的不同部分保存,这两个都可能会有问题。
使用第二个MOC是如何“假设”使用CoreData的;它会自动处理冲突检测和解决方案。当然,每次发生变化时,您都不希望创建新的MOC;如果您不介意UI的某些部分在其他部分看到未保存的更改(MOC间通信的开销可以忽略不计),那么缓慢的“用户线程”为未保存的更改提供一个MOC可能是模糊不清的。/ p>
答案 3 :(得分:8)
您可以使用NSManagedObjectContext
插入-[NSManagedObject initWithEntity:insertIntoManagedObjectContext:]
,并为托管对象上下文传递nil
。当然,您必须将其分配给上下文(在保存之前使用-[NSManageObjectContext insertObject:]
。据我所知,这并不是Core Data中的预期模式(但请参阅@ mzarra的回答{{3})有一些棘手的排序问题(即确保实例在它预期有一个之前被分配给一个上下文等)。更标准的模式是创建一个新的托管对象上下文并将你的新对象插入到上下文。当用户保存,保存上下文并处理NSManagedObjectDidSaveNotification
以将更改合并到您的“主要”上下文中时。如果用户取消交易,您只需吹走上下文并继续处理您的业务。
答案 4 :(得分:2)
可以使用nil作为上下文创建NSManagedObject,但是如果有其他NSManagedObject,它必须链接到它将导致错误。我这样做的方法是将上下文传递到目标屏幕并在该屏幕中创建一个NSManagedObject。使所有更改链接到其他NSManagedObjects。如果用户点击取消按钮,我删除NSManagedObject并保存上下文。如果用户点击保存按钮,我更新NSManagedObject中的数据,将其保存到上下文,然后释放屏幕。在源屏幕中,我使用重新加载更新表。
在目标屏幕中删除NSManagedObject会为核心数据提供更新文件的时间。这通常足够让您无法在tableview中看到更改。在iPhone日历应用程序中,从保存时间到它在tableview中显示的时间有延迟。从UI的角度来看,这可能是一件好事,您的用户将专注于刚刚添加的行。我希望这会有所帮助。
答案 5 :(得分:-2)
transaction = (Transaction *)[NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:nil];
如果最后一个参数是nil,它将返回NSManagedObject而不保存到db