有没有办法实例化NSManagedObject而不插入它?
我有一个用户界面来插入一个事务。 一旦用户点击一个加号,他得到的屏幕,我想实例化我的核心数据NSManagedObject实体,让用户在它上面工作。 然后当用户点击保存button,我将调用保存function。
所以下来代码:
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]
PS我在该表上使用NSFetchedResultsController,我看到NSFetchedResultsController插入一个节和一个对象的表。
我的想法是,如果有一种方法来实例化事务NSManagedObject我可以更新与保存,直到客户端select。
使用零MOC存在一个基本问题:不同MOC中的对象不应该相互引用 – 这大概也适用于关系的一方没有MOC的情况。 如果你保存,会发生什么? (当你的应用程序的另一部分保存时会发生什么?)
如果你的对象没有关系,那么你可以做很多事情(比如NSCoding)。
您可能能够在NSPredicate中使用-[NSManagedObject isInserted]
(推测在插入和成功保存之间是YES)。 或者,您可以使用具有相同行为的瞬态属性(在awakeFromInsert中将其设置为YES,在willSave中将其设置为NO)。 如果您的应用程序的不同部分保存,这两个可能会有问题。
然而,使用第二个MOC是CoreData“应该”被使用的方式; 它自动处理冲突检测和解决scheme。 当然,每次改变时你都不想创build一个新的MOC; 如果您不介意UI的某些部分在其他部分看到未保存的更改(MOC间通信的开销可以忽略不计),那么通过缓慢的“用户线程”可能有一个MOC用于未保存的更改可能是非常明智的。
对于什么是值得的,Marcus Zarra似乎正在推广nil
环境的方法,声称创build一个新的环境是很昂贵的。 有关更多详细信息,请参阅类似问题的答案 。
更新
我目前正在使用无环境的方法,并遇到了可能是其他人感兴趣的东西。 要创build一个没有上下文的托pipe对象,可以使用NSManagedObject
的initWithEntity:insertIntoManagedObjectContext:
方法。 根据苹果的这个方法的文档:
如果
context
不nil
,则此方法调用[context insertObject:self]
(这会导致调用awakeFromInsert
)。
这里的含义是重要的。 创build托pipe对象时使用nil
上下文将防止调用insertObject:
因此阻止调用awakeFromInsert
。 因此,在使用nil
上下文时,在awakeFromInsert
完成的任何对象初始化或默认属性值的设置都不会自动发生。
底线:使用没有上下文的托pipe对象时,不会自动调用awakeFromInsert
,您可能需要额外的代码进行补偿。
这是我的工作方式:
在负载上,我们知道我们正在处理一个新的交易,我创造了一个不合时宜的交易。
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Transaction" inManagedObjectContext:self.managedObjectContext]; transaction = (Transaction *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
那么当build立关系的时候,我这样做了:
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 }
你可以插入一个带有-[NSManagedObject initWithEntity:insertIntoManagedObjectContext:]
,为pipe理对象上下文传递nil
。 当然,你必须把它分配给一个上下文(在保存之前使用-[NSManageObjectContext insertObject:]
。这就是说,据我所知,这并不是真正意义上的核心数据模式(但请参阅@ mzarra的答案)。有一些棘手的顺序问题(例如确保实例在预期有一个上下文之前被分配到上下文等)。更为标准的模式是创build一个新的托pipe对象上下文,并将新的对象插入到上下文中。用户保存,保存上下文,并处理NSManagedObjectDidSaveNotification
将更改合并到“主”上下文中。如果用户取消事务,则只是吹掉上下文,继续与您的业务。
一个NSManagedObject可以使用nil作为上下文创build,但是如果有其他NSManagedObjects,它必须链接到它将导致错误。 我这样做的方式是将上下文传递到目标屏幕,并在该屏幕中创build一个NSManagedObject。 使所有更改链接其他NSManagedObjects。 如果用户点击取消button,我删除NSManagedObject并保存上下文。 如果用户点击保存button,我更新NSManagedObject中的数据,将其保存到上下文,并释放屏幕。 在源屏幕中,我使用重新加载来更新表格。
删除目标屏幕中的NSManagedObject会给核心数据更新文件的时间。 这通常足以让你在tableview中看不到变化。 在iPhone日历应用程序中,从保存时间到显示在桌面视图中的时间都有所延迟。 从UI的angular度来看,这可以被认为是一件好事,您的用户将专注于刚添加的行。 我希望这有帮助。
transaction = (Transaction *)[NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:nil];
如果最后一个参数是零,它将返回一个NSManagedObject而不保存到数据库