RestKit 0.20——创建新的 NSManagedObject 的首选方法是啥?

Posted

技术标签:

【中文标题】RestKit 0.20——创建新的 NSManagedObject 的首选方法是啥?【英文标题】:RestKit 0.20 — What is the preferred way to create a new NSManagedObject?RestKit 0.20——创建新的 NSManagedObject 的首选方法是什么? 【发布时间】:2012-12-06 20:54:13 【问题描述】:

我很想知道在 RestKit 0.20 中创建新的 NSManagedObject 的最佳方法是什么?目前我的代码看起来像这样:

#pragma mark - navigation buttons

- (void)createButtonDidTouch

    // create new album object    
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    NSManagedObjectContext *parentContext = RKObjectManager.sharedManager.managedObjectStore.mainQueueManagedObjectContext;
    context.parentContext = parentContext;
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Album" inManagedObjectContext:parentContext];
    Album *newAlbum = [[Album alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:context];

    // pass object to create view to manipulate
    AlbumCreateViewController *createViewController = [[AlbumCreateViewController alloc] initWithData:newAlbum];
    createViewController.delegate = self;
    createViewController.managedObjectContext = context;

    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:createViewController];
    navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;

    [self presentViewController:navController animated:YES completion:nil];


#pragma mark - create view controller delegate

- (void)createViewControllerDidSave:(NSManagedObject *)data

    // dismiss the create view controller and POST

    // FIXME: add restkit code to save the object
    NSLog(@"save the object...");

    NSDictionary *userInfo = [KeychainUtility load:@"userInfo"];
    NSString *path = [NSString stringWithFormat:@"/albums/add/%@/%@", userInfo[@"userID"], userInfo[@"apiKey"]];

    [RKObjectManager.sharedManager postObject:data path:path parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) 
        operation.targetObject = data;
     failure:^(RKObjectRequestOperation *operation, NSError *error) 
        NSLog(@"create album error: %@", error);
    ];

    [self dismissViewControllerAnimated:YES completion:nil];


- (void)createViewControllerDidCancel:(NSManagedObject *)data

    // dismiss the create view controller

    NSLog(@"delete the object...");
    // FIXME: add restkit code to delete the object

    [self dismissViewControllerAnimated:YES completion:nil];

我也很想知道我的职责是保存/删除这个对象。如果我通过 RestKit POST 到服务器,是否保存了托管对象上下文?

如果我决定取消这个创建过程——删除这个对象的首选方法是什么?

基本上,RestKit 为我做了多少,我应该确保我在做什么。我还没有找到太多关于这方面的文档,希望能清楚地说明这一点。

【问题讨论】:

【参考方案1】:

当您为给定对象初始化RKManagedObjectRequestOperation 时,RestKit 将获取该对象的永久对象 ID,然后创建一个子托管对象上下文,其父上下文是该对象插入的上下文。然后该操作执行 HTTP 请求以完成并获得响应。

如果响应成功且响应的映射成功(注意映射发生在此私有子上下文中),则保存私有子上下文。调用的保存类型由savesToPersistentStore 属性的值确定(请参阅http://restkit.org/api/0.20.0/Classes/RKManagedObjectRequestOperation.html#//api/name/savesToPersistentStore)。

YES 时,上下文通过NSManagedObjectContext 类别方法saveToPersistentStore 递归保存到持久存储区(请参阅http://restkit.org/api/0.20.0/Categories/NSManagedObjectContext+RKAdditions.html)。

NO 时,上下文通过普通的[NSManagedObjectContext save:] 消息保存,它将更改“推送”回父上下文。在您将它们保存回来之前,它们将保持在该上下文的本地。请记住,托管对象上下文父/子层次结构只要您在应用程序中创建即可。

如果 HTTP 请求失败或映射过程中出现错误,则不保存私有上下文并认为操作失败。这意味着不会将任何更改保存回原始 MOC,使您的对象图与开始操作之前一样(除了正在发送的对象,如果是临时的,现在具有永久对象 ID,但仍未保存)。

【讨论】:

我将如何删除这个对象——假设我用上面的代码创建了对象,但没有触发 POST 请求——而是取消/关闭“创建”视图控制器?只是通过我本地的 NSMagedObjectContext? 在上面的代码中,它被插入到上下文中,但未保存。您可以在关闭视图控制器时将其从上下文中删除。但我建议您NOT 将对象直接插入managedObjectStore.mainQueueManagedObjectContext,而是在您转到创建控制器并将其分配给控制器时创建一个子托管对象上下文。然后你可以做的就是在你取消时让 MOC 释放。 是否有创建子上下文的快捷方式?在我记得使用类似 [Album createObject] 或类似的东西之前。 如果您采用“传递接力棒”的方法,parentContext 将被设置为 self.managedObjectContext,然后您将该上下文分配给childViewController.managedObjectContext。通过这种方式,您将获得与导航堆栈匹配的上下文层次结构。如果child只是一个show view,可以直接传入self.managedObjectContext。这为您处理错误、通过丢弃上下文取消等提供了灵活性和隔离性。 真的可以使用一个刷新的代码示例来展示如何使用 RestKit 创建和保存 CoreData 对象。 RKGist 教程中的“创建 Gists”部分是空的。我不知道还能去哪里看。【参考方案2】:

你这样做的方式应该有效(每次调用每个 VC 中的 MOC),但不是“推荐”的。

就像任何 Core Data 应用程序一样,Apple 建议的是“传递接力棒”风格。

嵌套上下文使得采用 访问上下文的“传递接力棒”方法(通过传递上下文 从一个视图控制器到下一个)而不是检索它 直接来自应用程序委托。

请看这里: http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-CoreData/_index.html

至于你的第二个问题,如果一切都很好地映射/设置,RestKit 应该在你的 api 调用成功后管理保存/更新你的核心数据堆栈。

来自 RK 创建者布莱克:

如果你 POST 或 PUT 一个 Core Data 对象,RK 会获得一个永久对象 它的 ID,然后创建一个辅助托管对象上下文,触发 请求,并映射响应(如果可能)。如果响应和 映射成功,它会将其保存回父级 上下文或一直回到持久存储(即进入 SQLite) 基于 savesToPersistentStore 的值。

【讨论】:

以上是关于RestKit 0.20——创建新的 NSManagedObject 的首选方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Restkit 0.20:在自己的静态库中构建存档时找不到

在 restKit 0.20 中删除孤立对象

无法使用 RestKit 0.20 在构建之间持久化数据

从 RestKit 0.10 更新到 0.20

RestKit 0.20 映射问题

restkit 版本 0.20 上的 fetchRequest - 没有已知的类方法