核心数据不会持久保存对象

时间:2013-08-17 02:47:27

标签: ios objective-c core-data ios6

我是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文件并检查添加的对象时,我意识到它没有向数据库添加任何对象。

在应用程序重新启动时,我打印出已存在于数据库中的对象列表,并确认我尚未保存。

有没有人知道发生了什么以及为什么我无法持久保存数据,即使看起来我已经成功创建了需要保存在Core Data模型中的'User'对象。

编辑:

这是我创建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是后台和新后台的父级。当我查询这样的上下文时:

    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,并为@“查询记录”提供下面的输出

   (
    "<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”会为(null)中的obj.id返回NSLog并返回@"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>)"
)

8 个答案:

答案 0 :(得分:12)

从您的代码和注释中,您似乎没有保存主上下文。请务必致电

[managedObjectContext save:&error]; 

用于保存数据的所有子上下文,以及之后在主上下文中。

答案 1 :(得分: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

save函数给出了一个YES布尔返回值,saveError仍为零,但如果我退出应用程序并重新启动,当我的Core Data加载我的NSManagedObject子类时,data属性为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的线程上这样做。

答案 2 :(得分:5)

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

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

另一种看待这些类型问题的方法就是解决问题。也许对象实际上是保存的,但是你验证它们实际上已经被保存的方法是错误的。通常,您可以通过使用特定条件查询CoreData以获取记录来执行此操作。仔细检查您的条件是否正确,以及您的查询实际上是否返回了您的期望。

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

答案 3 :(得分: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"];
    }
}

答案 4 :(得分:2)

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

我在保存数据方面遇到了一些问题,似乎有什么东西可以帮助我修复它。结构非常简单,一个实体有一个字段和一个关系(to-many)。我对生成的类NSMutableOrderedSet而不是NSOrderedSet进行了一些更改。

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

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

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

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

答案 5 :(得分:2)

保存数据后添加:

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

答案 6 :(得分:0)

经过数小时的调试后,我发现我的更新未被保存的原因是因为我的NSManagedObject子类是由属性w / @synthesize而不是@dynamic定义的}。

更改后,所有内容都按预期保存。

希望有人帮助过。

答案 7 :(得分:0)

如果缺少与对象没有逆关系的对象,则需要在映射之前保存两个实体。选中我创建的example来演示 对于没有反向关系的情况,在处理核心数据时核心数据对象如何丢失以及如何解决。

相关问题