在Core Data中创建新对象:首先创建还是返回?

时间:2012-05-01 00:32:21

标签: ios core-data nsmanagedobject

所以我在与Core Data斗争。我发现有很多方法可以做同样的事情,如果你尝试使用Storyboards和UIManagedDocuments构建应用程序,你需要阅读比去年更早的所有教程和示例以及翻译表。今天的问题是在添加新的托管对象时找到最佳实践。我见过两种方式的例子:

  1. 在表视图控制器中创建新的托管对象(在单击+之后)并将新的闪亮托管对象提供给从属“添加”视图控制器以获取所有对象属性的用户输入。这看起来很简单,返回的对象很容易理解,因为它包含所有单独的属性。但是我在这个“添加”视图控制器中看到了一个“取消”按钮的示例代码,该按钮删除传入的托管对象,然后在解除自身之前调用Save Context。功能齐全,但我肩上的MVC训练侏儒对我说这个从属的Add View删除一个对象而恐怖直接调用Save Context。 Apple的Recipe示例代码似乎使用此方法。

  2. 不向“添加”视图控制器发送任何内容,并让它向代理调用发回一个表视图控制器,该控制器将每个属性作为单独的传递参数返回。所以return方法变得非常长:controller:(UIViewController *)controller didReturnFirstName:(NSString *)firstName andLastName:(NSString *)lastName andStreetAddress:(NSString *)and ... and ... and ..但这是SO与MVC教条一致,因为托管对象在接收所有单个属性时在表视图控制器中创建,并且“添加”视图从不接触模型(核心数据),或者在用户更改时丢弃未使用的托管对象他们的想法 即使使用链式委托方法,我仍然在与自己辩论,这是一种更好的方法。来自那些使用这两种形式的人的评论和想法将是一个受欢迎的补充。

  3. 感谢。

4 个答案:

答案 0 :(得分:1)

你看一下Apple的tutorial中的例子,他们通过做下面列出的一些事情完成了这个任务,在这种情况下,他们有一个模态视图似乎输入要添加到数据模型:

  1. 在出现的模态视图中,他们创建了一个协议来处理解除视图或保存数据的问题,以及一个实现该协议的类型为id的属性作为delagate,这可以保证任何对象的实现。必要的方法

  2. 在创建模态视图的视图控制器中,它们实现协议,包括将对象保存到数据模型并解除模态视图

  3. 在创建模态的视图控制器中,他们将创建模态视图的视图控制器设置为模式视图中的模态视图委托

  4. 因此,总而言之,在收集新数据的模态视图中,您需要: 在.h中创建协议和属性并合成它

     @protocol yourProtocol <NSObject>;
     //methods that determine what happens based on what user does, it would save your core data object
     @end
    
     @property(nonatomic, weak) id<yourProtocol> delegate;
    

    然后,在模态视图.m文件中,您可以在委托上调用这些方法,可能是在他们选择保存或完成时,因此每个方法都可能作为IBAction连接到按钮

     [self.delegate myMethod];
    

    在呈现模态视图的视图中,您在.h文件中实现协议

     @interface viewController() <yourProtocol>
    

    最后,将您的方法添加到呈现模态视图的.m文件的视图控制器中,这应包括删除视图并保存核心数据。根据Apple和其他消息来源,导致弹出/模态等的视图控制器应该是解散它的视图控制器。然后,在使用seque indentfying的seque中,将模态视图中显示的视图控制器设置为模态视图的委托。

答案 1 :(得分:1)

你是对的,有很多方法可以采取这个。

听起来好像你是从一个可能无法保存的上下文开始的,所以为了能够回到你的起点,我会像这样解决它:

  1. 首先创建一个新的NSManagedObject,作为临时对象传递到“编辑”视图。
  2. 如果您正在编辑现有对象,请将现有对象中的属性复制到此新临时对象中(您可以使用快速for循环将它们全部复制)。否则继续使用新创建的对象。
  3. 将临时对象传递给“编辑”视图控制器,并将它们视为两个案例相同 一个。如果用户按下取消,则使用协议或委托方法通知tableview和tableview,然后只丢弃临时对象。
    湾如果他们按保存,则通知tableview,然后将临时副本中的属性复制回原始对象并删除临时对象(如果是编辑操作),或者将其保留为新创建的对象(如果是“添加”) “操作。

答案 2 :(得分:0)

我认为正确的方法实际上是为您的AddController(如果要创建新项目)或EditController(如果要修改现有项目)创建一个新的单独NSManagedObjectContext

根据您的SDK选择A)或B):

A)然后您可以选择保存该上下文中的更改,或者丢弃上下文。

如果是“保存”,您可以通过通知(ManagedObjectContext将更改合并到TableController的NSManagedObjectDidSaveNotification

如果是“取消”,您可以放弃单独的上下文。

B)或者,如果你使用的是OSX 10.7(+),你可以使用嵌套的NSManagedObjectContext,在AddController中创建一个NSManagedObjectContext(子上下文),并将它的parentContext设置为TableController的NSManagedObjectContext

如果是“保存”,您将保存子上下文和父上下文。

如果是“取消”,您只需丢弃子上下文。

在Apple的CoreDataBooks示例http://developer.apple.com/library/ios/#samplecode/CoreDataBooks/Introduction/Intro.html

中查看详细示例

答案 3 :(得分:0)

这不是一个真正的答案,所以可以随意忽略,但其他任何一个(到目前为止)都没有完整答案,我觉得有必要在不创建新问题的情况下添加一些要点,因为我真的很想深入了解这一点。特别是答案应该处理

  • 取消vs保存时会发生什么
  • 如果您想使用同一个控制器编辑现有实体而不是创建新实体
  • ,该怎么办?

尼克斯回答处理苹果(当前)传递数据的惯例,但不是一个完整的答案,因为该教程不处理核心数据管理对象,苹果自己的使用托管对象的样本做的不同。 / p>

但是在这个问题上,我发现代理约定在某些情况下是不实用的,并且很高兴从一个更有经验的开发人员那里读到这个: http://robsprogramknowledge.blogspot.pt/2012/05/back-segues.html

Rob详细介绍了所有同等有效的机制,包括协议/委托约定(Nick's),使用没有协议的数据对象(所谓的“共享内存”) - 更多像其他人建议的一样,而且 - 我最喜欢的 - 使用一个块。 块是一个不错的选择,因为虽然它像委托一样工作,但代码仍然完全在“父”视图控制器源中的上下文中

但是,“共享内存”更有意义,因为正如您所说的那样,使用除了您已经设计的数据(托管)对象之外的任何其他内容来传递所有这些属性看起来很傻。

对我来说,问题是,创建这些托管对象的惯例是什么,传递它们,然后 1.保存更改 2.取消变更 3.完全取消创建新实体

Inafzigers上面的回答是这样的,但为什么复制属性?我不能不保存我的更改吗?

Apple的CoreDataBooks似乎通过在prepareForSegue和委托方法(当它返回时)中创建 ManagedObjectContext和该上下文中的新实体(insertNewObjectForEntityForName)来解决这个问题: - 如果单击了Save,则会保存此新ManagedObjectContext和父FetchedResultsContext以存储对象 - 如果单击取消,它什么都不做,有效地丢弃新的托管对象上下文,因此,可能是新对象

所以这个可能是传统的方法,除了:

  • 该示例的代码(CoreDataBooks RootViewController.m)中有一条注释,其中指出两个托管上下文不是必需的,这意味着您可能只能使用一个托管上下文。以下是完整评论:    重要提示:没有必要为此使用第二个上下文。您可以使用现有的上下文,这将简化一些代码 - 例如,您不需要执行两次保存。但是,此实现说明了一种有时可能有用的模式(您希望维护一组单独的编辑)。

  • CoreDataBooks不使用UIManagedDocument - 不确定是否会产生影响

我不清楚的是,我们真的要使用insertNewObjectForEntityForName来创建托管对象吗?如果用户点击Save?

,只需创建对象然后再插入它就可以了

如果我们进行编辑和取消,那么我们可以使用撤消管理器来摆脱变化吗?