58

我有一个用户界面来插入交易。一旦用户点击加号,他就会得到屏幕,我想实例化我的核心数据 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]

PS 我在该表上使用 NSFetchedResultsController,我看到 NSFetchedResultsController 正在向表中插入一个部分和一个对象。

我的想法是,如果有一种方法可以实例化 Transaction NSManagedObject,我可以在不保存的情况下更新它,直到客户选择为止。

4

6 回答 6

38

值得一提的是,Marcus Zarra 似乎在推广nil上下文方法,声称创建新上下文的成本很高。有关更多详细信息,请参阅对类似问题的回答。

更新

我目前正在使用 nil 上下文方法,并且遇到了其他人可能感兴趣的事情。要创建没有上下文的托管对象,请initWithEntity:insertIntoManagedObjectContext:使用NSManagedObject. 根据 Apple 对此方法的文档:

如果context不是nil,则此方法调用[context insertObject:self] (导致awakeFromInsert被调用)。

这里的含义很重要。nil在创建托管对象时使用上下文将阻止insertObject:被调用,因此阻止awakeFromInsert被调用。因此,在使用上下文时,任何对象初始化或默认属性值的设置awakeFromInsert都不会自动发生。nil

底线:当使用没有上下文的托管对象时,awakeFromInsert不会自动调用,您可能需要额外的代码来补偿。

于 2010-10-06T00:01:39.263 回答
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
    }
于 2010-10-06T14:34:30.843 回答
18

使用 nil MOC 有一个基本问题:不同 MOC 中的对象不应该相互引用——这大概也适用于当关系的一方有一个 nil MOC 时。如果你保存会发生什么?(当您的应用程序的另一部分保存时会发生什么?)

如果您的对象没有关系,那么您可以做很多事情(例如 NSCoding)。

您可能可以-[NSManagedObject isInserted]在 NSPredicate 中使用(大概在插入和成功保存之间是 YES)。或者,您可以使用具有相同行为的瞬态属性(在 awakeFromInsert 中将其设置为 YES,在 willSave 中将其设置为 NO)。如果您的应用程序的不同部分保存,这两者都可能有问题。

不过,使用第二个 MOC 是“应该”使用 CoreData 的方式;它会自动为您处理冲突检测和解决。当然,您不希望每次发生变化时都创建一个新的 MOC;如果您不介意 UI 的某些部分在其他部分看到未保存的更改(MOC 间通信的开销可以忽略不计),那么使用一个 MOC 来处理缓慢的“用户线程”未保存的更改可能是模糊的明智之举。

于 2010-10-06T00:51:50.147 回答
8

您可以插入一个NSManagedObjectContextwith -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:],传递nil托管对象上下文。当然,您必须将其分配给上下文(-[NSManageObjectContext insertObject:]在保存之前使用。据我所知,这并不是 Core Data 中真正的预期模式(但请参阅@mzarra 的答案here)。有一些棘手的排序问题(即确保实例在它期望有一个上下文之前被分配给一个上下文,等等)。更标准的模式是创建一个新的托管对象上下文并将新对象插入到该上下文中。当用户保存时,保存上下文,并处理将NSManagedObjectDidSaveNotification更改合并到您的“主要”上下文中。如果用户取消事务,您只需删除上下文并继续您的业务。

于 2010-10-05T23:34:40.770 回答
2

可以使用 nil 作为上下文创建 NSManagedObject,但如果有其他 NSManagedObject 必须链接到它,则会导致错误。我这样做的方式是将上下文传递到目标屏幕并在该屏幕中创建一个 NSManagedObject 。使所有更改链接其他 NSManagedObjects。如果用户点击取消按钮,我将删除 NSManagedObject 并保存上下文。如果用户点击保存按钮,我会更新 NSManagedObject 中的数据,将其保存到上下文中,然后释放屏幕。在源屏幕中,我通过重新加载来更新表。

在目标屏幕中删除 NSManagedObject 会给核心数据时间来更新文件。这通常足以让您看不到 tableview 中的变化。在 iPhone 日历应用程序中,从保存时间到显示在表格视图中的时间存在延迟。从 UI 的角度来看,这可能被认为是一件好事,您的用户将专注于刚刚添加的行。我希望这有帮助。

于 2012-06-29T14:42:49.243 回答
-2
transaction = (Transaction *)[NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:nil];

如果最后一个参数为 nil,它将返回一个 NSManagedObject 而不保存到 db

于 2013-06-26T06:25:35.053 回答