【问题标题】:Core Data not saving objects persistently核心数据不持久保存对象
【发布时间】:2013-08-19 12:38:54
【问题描述】:

我是 Core Data 的新手,因此我不确定我是否犯了错误。我从 REST API 下载了一些数据,它成功地将 JSON 响应保存到磁盘。我正在尝试处理数据并使用 Core Data 持久保存它。

NSLog(@"inserted objects: %@", [managedObjectContext insertedObjects]);
    [managedObjectContext performBlockAndWait:^{
        NSError *error = nil;
        if (![managedObjectContext save:&error]) {
            NSLog(@"Unable to save context for class %@", className);
        } else {
            NSLog(@"saved all records!");
        }
    }];

我已成功处理 JSON 并将其添加到 NSManagedObjectContext。在第一行中,它显示我已成功尝试插入 2 个对象。

inserted objects: {(
    <User: 0xa259af0> (entity: User; id: 0xa259b70 <x-coredata:///User/t44BB97D0-C4B4-4BA6-BD25-13CEFDAE665F3> ; data: {
    email = "vishnu@vishnuprem.com";
    experience = "2013-07-20";
    "first_name" = Vishnu;
    id = 2;
    "job_title" = Developer;
    "last_name" = Prem;
    location = "";
    "phone_number" = "+6590091516";
    "profile_pic" = "";
    "thumbnail_profile_pic" = "";
    "user_id" = 2;
}),
    <User: 0xa25e460> (entity: User; id: 0xa25e4c0 <x-coredata:///User/t44BB97D0-C4B4-4BA6-BD25-13CEFDAE665F2> ; data: {
    email = "sanchitbareja@gmail.com";
    experience = "2013-07-20";
    "first_name" = Sanchit;
    id = 1;
    "job_title" = Developer;
    "last_name" = Bareja;
    location = "";
    "phone_number" = "+15106127328";
    "profile_pic" = "";
    "thumbnail_profile_pic" = "";
    "user_id" = 1;
})
)}

当我尝试[managedObjectContext save:&amp;error] 时,它成功并按预期打印出“已保存所有记录”。但是,当我转到我的应用程序 .sqlite 文件并检查添加的对象时,我意识到它没有向数据库添加任何对象。

在应用程序重新启动时,我打印出数据库中已经存在的对象列表,它确认我还没有保存任何对象。

有谁知道发生了什么以及为什么我无法持久保存数据,即使看起来我已经成功创建了需要保存在核心数据模型中的“用户”对象。

编辑:

这里是我创建NSPersistentStoreCoordinator的地方

// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"RTModel.sqlite"];

    NSError *error = nil;
    NSLog(@"Test 1");
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    NSLog(@"Test 2");

    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        /*
         Replace this implementation with code to handle the error appropriately.

         abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

         Typical reasons for an error here include:
         * The persistent store is not accessible;
         * The schema for the persistent store is incompatible with current managed object model.
         Check the error message to determine what the actual problem was.


         If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.

         If you encounter schema incompatibility errors during development, you can reduce their frequency by:
         * Simply deleting the existing store:
         [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]

         * Performing automatic lightweight migration by passing the following dictionary as the options parameter:
         [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

         Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.

         */
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return _persistentStoreCoordinator;
}

我有 3 个上下文。

  • masterManagedObjectContext

  • backgroundManagedObjectContext

  • newManagedObjectContext

master 是 background 和 new 的父级。当我像这样查询上下文时:

    NSError *error = nil;
    NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"User"];
    [request setSortDescriptors:[NSArray arrayWithObject:
                                 [NSSortDescriptor sortDescriptorWithKey:@"id" ascending:YES]]];
    [request setReturnsObjectsAsFaults:NO];
    NSArray *testArray = [[[RTCoreDataController sharedInstance] newManagedObjectContext] executeFetchRequest:request error:&error];

    for (User *obj in testArray) {
        NSLog(@"obj.id %@", obj.id);
    }

    NSLog(@"query records: %@",testArray);

master 和 background 都在 NSLog 中返回正确的 obj.id 并为@"query records" 提供下面的输出

   (
    "<User: 0xa3811d0> (entity: User; id: 0xa381230 <x-coredata:///User/t92BCED2D-CD17-49CC-9EBA-DF8F52F06A002> ; data: {\n    email = \"sanchitbareja@gmail.com\";\n    experience = \"2013-07-20\";\n    \"first_name\" = Sanchit;\n    id = 1;\n    \"job_title\" = Developer;\n    \"last_name\" = Bareja;\n    location = \"\";\n    \"phone_number\" = \"+15106127328\";\n    \"profile_pic\" = \"\";\n    \"thumbnail_profile_pic\" = \"\";\n    \"user_id\" = 1;\n})",
    "<User: 0xa382170> (entity: User; id: 0xa3820b0 <x-coredata:///User/t92BCED2D-CD17-49CC-9EBA-DF8F52F06A003> ; data: {\n    email = \"vishnu@vishnuprem.com\";\n    experience = \"2013-07-20\";\n    \"first_name\" = Vishnu;\n    id = 2;\n    \"job_title\" = Developer;\n    \"last_name\" = Prem;\n    location = \"\";\n    \"phone_number\" = \"+6590091516\";\n    \"profile_pic\" = \"\";\n    \"thumbnail_profile_pic\" = \"\";\n    \"user_id\" = 2;\n})"
)

然而,“new”为NSLog 中的obj.id 返回(null),并为@"query records" 返回以下内容:

(
    "<User: 0xa2b08a0> (entity: User; id: 0x95aebe0 <x-coredata:///User/tBFCC6C5F-7D2C-4AA0-BA96-B806EE360A762> ; data: <fault>)",
    "<User: 0xa2b0910> (entity: User; id: 0xa4b9780 <x-coredata:///User/tBFCC6C5F-7D2C-4AA0-BA96-B806EE360A763> ; data: <fault>)"
)

【问题讨论】:

  • 您可以在创建NSPersistentStoreCoordinatorNSManagedObjectContext 的位置发布您的代码吗?如果这些配置错误,将有助于在那里看到它。
  • @JeffKelley 进行了相关编辑!我按照这里的教程 (raywenderlich.com/15916/…) 进行了操作,它可以工作,但是当我尝试为我自己的 REST API 自定义它时,它失败了。
  • 您是否得到“保存所有记录!”记录插入的对象后?
  • 是的,我确实得到了“保存所有记录”!
  • 您是否在使用多个托管对象上下文?可能你们有的有亲子关系,而你只救了一个孩子?

标签: ios objective-c core-data ios6


【解决方案1】:

从您的代码和 cmets 看来,您没有保存主上下文。确保你打电话

[managedObjectContext save:&error]; 

在所有保存数据的子上下文上,之后在主上下文上也是如此。

【讨论】:

  • 嗯,我试过这样做,但仍然没有区别。由于某种原因,数据仍然没有保留。
  • 这应该是正确的答案。我刚才遇到了同样的问题,在阅读了这篇文章后,我尝试将整个上下文层次结构强制保存在一个循环中。程序终于成功了。
  • 我的方法是拥有一个全局函数(在核心数据堆栈或应用程序委托中)saveContext,它可以保存所有内容,并且我可以从任何地方安全地调用它。
  • 是的,这是必要的,也给我带来了一些痛苦,因为核心数据文档没有提到这一点。我还建议在主队列上调用它。
  • @RunLoop 但前提是已经在主上下文中创建了上下文!
【解决方案2】:

我刚刚解决了基本相同的问题。 UITableViewController 从 NSManagedObjectContext 中获取 NSManagedObject 的子类,检查属性是否为 nil,如果已下载数据,则设置该属性,然后保存 NSManagedObjectContext。像这样的:

MyManagedObject *mgObject = //get object from NSFetchResultsController
NSManagedObjectContext *mgObContext = mgObject.managedObjectContext;
if (!mgObject.data)
{
    mgObject.data = [NSData dataWithContentsOfURL:urlWithData];
    [mgObContext performBlock ^{
        NSError *saveError = nil;
        BOOL saveResult = [mgObContext save:&saveError];
        if (saveError || !saveResult)
        {
            NSLog(@"Save not successful..");
        }
    }];
}
//do something with myObject.data

保存函数返回 YES 布尔值,并且 saveError 保持为零,但如果我退出应用程序并重新启动,当我的核心数据加载我的 NSManagedObject 子类时,数据属性为 nil,并且当这个 UITableViewController 恢复时,它必须重新下载数据。

我真的无法在任何地方找到解决方案……阅读 Core Data 文档并没有帮助。当我考虑到上面的代码和我在 NSManagedObject 子类的工厂方法中设置属性的代码之间的区别时,我想到了解决方案,基本上是:

MyManagedObject *mgObject = [NSEntityForDescription insertNewObjectForEntityName:@"MyManagedObject" inManagedContext:mgObContext];
mgObject.attribute1 = some value
mgObject.attribute2 = another value

唯一的区别是我从 [mgObContext performBlock:] 内部调用工厂方法。

所以修改后的代码是:

MyManagedObject *mgObject = //get object from NSFetchResultsController
NSManagedObjectContext *mgObContext = mgObject.managedObjectContext;
if (!mgObject.data)
{
    [mgObContext performBlock: ^{
        mgObject.data = [NSData dataWithContentsOfURL:urlWithData];
        NSError *saveError = nil;
        BOOL saveResult = [mgObContext save:&saveError];
        if (saveError || !saveResult)
        {
            NSLog(@"Save not successful..");
        }
    }];
}
//do something with myObject.data

到目前为止,它运行良好。所以我认为任何时候你对 NSManagedObjects 的属性进行修改,你都需要在他们的 NSManagedObjectContext 的线程上这样做。

【讨论】:

  • 谢谢,这是我的问题。
【解决方案3】:

我想我也会向可能有类似问题的人添加一些意见。

根据我的经验,尝试保存未填写足够字段的对象在保存时似乎不会持续存在,并且在这种情况下似乎不会引发错误。在保存触发之前,请务必仔细检查您的字段是否按预期填写。

看待这些类型问题的另一种方法是将问题翻转过来。也许对象确实保存了,但是您验证它们实际上已保存的方法是错误的。通常,您可以通过使用某些条件查询 CoreData 的记录来做到这一点。仔细检查您的条件是否正确,以及您的查询实际上是否返回了您期望的内容。

如果它没有返回您期望的结果,可能是由于您自己的错误,但也可能是存储结果的数组没有正确存储它们。在我不得不重命名NSArray 之前遇到过一些情况,因为有关数组名称的某些内容导致了引用问题,因此数组无法指向我期望的结果。干杯。

【讨论】:

    【解决方案4】:

    保存数据后添加:

    NSError *error = nil;
    if (![managedObjectContext save:&error]) {
        NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
    }
    

    【讨论】:

      【解决方案5】:

      我知道这不是 OP 所要求的答案,但我想分享我对同一主题的经验,以防它对其他人有所帮助。

      我在持久保存数据方面遇到了一些问题,似乎任何东西都可以帮助我解决它。结构非常简单,一个具有一个字段和一个关系(对多)的实体。我对生成的类进行了一些更改,NSMutableOrderedSet 而不是NSOrderedSet

      我没有做多线程或类似的事情,只是在关系中添加元素。保存并重新启动应用程序后,数据就消失了(添加到关系中的元素)。

      我最终发现有一个名为updated 的属性。将新元素添加到关系后,我检查了此属性是否更改了它的值。它没有。所以我不得不在实体中创建另一个字段,一个布尔值,以便能够在向该关系添加元素后强制保存实体。

      entity.addObject(..)
      entity.forceUpdate = true // without this line, it won't update
      managedContext.save(..)
      

      所以我希望它可以帮助任何有同样问题的人,因为我花了一些时间认为我没有正确保存它..

      【讨论】:

      • 我搜索了整个 cocoa 文档,发现任何地方都没有 forceUpdate 属性...
      • @SpaceDog 现在已经 2 年了,所以我不记得细节了,但是为了确定该属性不是框架的一部分,我将它添加到实体中(正如我在答案中所说)。似乎只是将对象添加到关系中并没有触发持久保存它,但是更新这个另一个值就可以了。
      【解决方案6】:

      我是 iOS 的初学者,但我使用 CoreData 做了一些示例来存储用户信息。

      首先,您需要使用您的实体创建模型(我想您已经完成了)。在我的示例中,我的实体称为“用户”。

      首先,添加一个类似这样的属性

      NSManagedObjectContext *context;
      

      到您的 ViewController 类。

      其次,在你的 viewDidLoad 方法中,添加这两行:

      AppDelegate *appdelegate = [[UIApplication sharedApplication]delegate];
      context = [appdelegate managedObjectContext];
      

      第三,存储您的信息:

      NSEntityDescription *entitydesc = [NSEntityDescription entityForName:@"User" inManagedObjectContext:context];
      NSManagedObject *newUser = [[NSManagedObject alloc]initWithEntity:entitydesc insertIntoManagedObjectContext:context];
      [newUser setValue:(NSString *)[dictionary objectForKey:@"name"] forKey:@"name"];
      [newUser setValue:(NSString *)[dictionary objectForKey:@"surname"] forKey:@"surname"];
      ...
      
      NSError *error;
      [context save:&error];
      

      (我从一个叫做字典的 NSDictionary 中获取我的属性)

      阅读您的信息:

      AppDelegate *appdelegate = [[UIApplication sharedApplication]delegate];
      context = [appdelegate managedObjectContext];
      NSEntityDescription *entitydesc = [NSEntityDescription entityForName:@"User" inManagedObjectContext:context];
      NSFetchRequest *request = [[NSFetchRequest alloc]init];
      [request setEntity:entitydesc];
      
      //NSPredicate *predicate = [NSPredicate predicateWithFormat:@"NULL"];
      [request setPredicate:nil];
      
      NSError *error;
      NSArray *matchingData = [context executeFetchRequest:request error:&error];
      //NSArray *matchingData = [context executeFetchRequest:nil error:&error];
      
      // If the user is not logged in previously
      if (matchingData.count <=0 ){
          //self.displaylabel.text = @"No person find";
      } else {
      // If the user is already logged in
          for (NSManagedObject *obj in matchingData) {
              AppDataModel *appDataModel=[AppDataModel getInstance];
              appDataModel.appUserInfo = [User alloc]; 
              appDataModel.appUserInfo.name = [obj valueForKey:@"name"];
              appDataModel.appUserInfo.surname = [obj valueForKey:@"surname"];
          }
      }
      

      【讨论】:

      • 非常感谢!我最终最终从头开始构建应用程序,但一开始我不知道出了什么问题!非常感谢您的帮助!
      【解决方案7】:

      经过数小时的调试,我发现我的更新没有被保存的原因是因为在我的 NSManagedObject 子类中,我通过带有 @synthesize 而不是 @dynamic 的属性定义。

      我修改后,一切都按预期保存了。

      希望对某人有所帮助。

      【讨论】:

        【解决方案8】:

        如果在没有反向关系的地方缺少对象,则需要在映射之前保存两个实体。检查这个example,我创建它是为了演示 核心数据对象如何丢失以及如何解决,在使用核心数据时,在您没有反向关系的情况下

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-30
          相关资源
          最近更新 更多