19

我是 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:&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})"
)

但是“新”返回(null)obj.id inNSLog并返回以下内容@"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>)"
)
4

8 回答 8

13

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

[managedObjectContext save:&error]; 

在所有保存数据的子上下文上,然后主上下文上。

于 2013-08-17T22:22:23.010 回答
10

我刚刚完成了对基本相同问题的尝试。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 的线程上这样做。

于 2014-03-09T03:04:58.447 回答
8

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

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

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

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

于 2015-10-27T22:32:29.510 回答
4

保存数据后添加:

NSError *error = nil;
if (![managedObjectContext save:&error]) {
    NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
}
于 2016-10-13T08:12:09.143 回答
3

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

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

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

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

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

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

于 2015-03-03T09:10:39.910 回答
2

我是 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"];
    }
}
于 2013-08-19T14:39:07.777 回答
0

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

于 2019-10-15T17:07:03.187 回答
0

经过数小时的调试,我发现我的更新没有被保存的原因是因为在我的子类中NSManagedObject我由属性 w/@synthesize而不是@dynamic.

更改后,一切都按预期保存。

希望对某人有所帮助。

于 2017-03-26T19:30:14.853 回答