2013-08-17 4 views
14

Я новичок в 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 = "[email protected]"; 
    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 = "[email protected]"; 
    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 и проверяю наличие добавленных объектов, я понимаю, что он не добавил никаких объектов в db.

При повторном подключении я распечатываю список объектов, которые уже находятся в базе данных, и подтверждает, что я еще не сохранил.

Кто-нибудь знает, что происходит, и почему я не могу сохранить данные настойчиво, хотя похоже, что я успешно создал объекты «Пользователь», которые необходимо сохранить в модели Core Data.

EDIT:

здесь, где я создаю 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

мастер родитель как фон и новый. Когда я запрашиваю контексты, как это:

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); 

мастеров и фон возвращает правильный obj.id в NSLog, а также дает выход ниже @ «запись запроса»

(
    "<User: 0xa3811d0> (entity: User; id: 0xa381230 <x-coredata:///User/t92BCED2D-CD17-49CC-9EBA-DF8F52F06A002> ; data: {\n email = \"[email protected]\";\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 = \"[email protected]\";\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 в 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>)" 
) 
+0

Можете ли вы разместить свой код, где вы создаете свой 'NSPersistentStoreCoordinator' и' NSManagedObjectContext'? Если они неправильно сконфигурированы, это поможет увидеть их там. –

+0

@JeffKelley сделал соответствующие изменения! Я прошел через учебник здесь (http://www.raywenderlich.com/15916/how-to-synchronize-core-data-with-a-web-service-part-1), и он работает, но когда я попытался настроить это для моего собственного REST API, он терпит неудачу. –

+1

Вы получили «сохраненные записи!». после регистрации вставленных объектов? –

ответ

11

Из кода и Commen Кажется, что вы не сохраняете главный контекст. Убедитесь, что вы звоните

[managedObjectContext save:&error]; 

на все дочерние контексты, сохранить данные, и после что на главном контексте.

+0

Хмм, я попытался сделать это, и все еще не было никакой разницы. По какой-то причине данные по-прежнему не сохраняются. –

+1

Это должен быть правильный ответ. Я встретил ту же проблему только сейчас, и после прочтения этого сообщения я попытался принудительно сохранить всю иерархию контекста в цикле. Наконец, программа работала. – Chris

+1

Мой подход состоит в том, чтобы иметь глобальную функцию (в стеке Core Data или делегат приложения) 'saveContext', который сохраняет все и что я могу звонить из любой точки мира безопасно. – Mundi

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"]; 
    } 
} 
+1

Спасибо большое! В конечном итоге я закончил создание приложения с нуля, но не смог понять, что пошло не так, в первую очередь! Большое спасибо за помощь! –

9

Я только что ударил, ударив головой по той же проблеме. UITableViewController извлекал подкласс NSManagedObject из NSManagedObjectContext, проверял, был ли атрибут нулевым, и если он был загружен данными, установите этот атрибут, а затем сохранили 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 атрибут данных был равен нулю , и когда этот 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.

+1

Спасибо, это была моя проблема. –

2

Я знаю, что это не ответ на вопрос, который задал ОП, но я хотел поделиться своим опытом о том же предмете, если он поможет кому-то другому.

У меня возникли проблемы с сохранением данных настойчиво, что-то помогло мне исправить это. Структура была очень простой: сущность с одним полем и одно отношение (для многих). Я внесла некоторые изменения в генерируемый класс, NSMutableOrderedSet вместо NSOrderedSet.

Я не делал многопоточность, или что-то в этом роде, просто добавляя элементы в отношения. После сохранения и повторного запуска приложения данные просто исчезли (элементы добавлены в отношение).

В итоге я обнаружил, что есть свойство под названием updated. После добавления нового элемента в отношение, я проверил, изменило ли это свойство его значение. Это не так. Поэтому мне пришлось создать другое поле в Entity, логическом, просто чтобы заставить объект быть сохраненным после добавления элементов к этим отношениям.

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

Так что я надеюсь, что это помогает кто с такой же проблемой, как я провел некоторое время, думая, что я не спасал его правильно ..

+1

Я искал всю документацию по какао и нет никакого свойства forceUpdate в любом месте ... – SpaceDog

+0

@SpaceDog прошло уже 2 года, поэтому я не могу запомнить детали, но наверняка, что свойство не является частью фреймворка, я добавил его (как я сказал в ответе). Кажется, что просто добавление объекта в отношение не вызывало его, чтобы сохранить его настойчиво, но обновление этого другого значения сделало трюк. –

4

Фигурные Я хотел бы также добавить некоторые материалы для людей, которые могут иметь аналогичные вопросы.

По моему опыту, при сохранении объектов, которые не заполняют достаточное количество полей, при сохранении, похоже, не сохраняются, и при этом не возникает ошибок. Всегда проверяйте, чтобы ваши поля заполнялись, как ожидалось, до сохранения огня.

Еще один способ взглянуть на эти проблемы - перевернуть проблему на голове. Возможно, объект действительно сохранил, но метод, в котором вы проверяете, что они были фактически сохранены, неверен. Часто вы можете сделать это, запросив CoreData для записи (ов), используя определенные критерии. Дважды проверьте, что ваши критерии верны и что ваш запрос действительно возвращает то, что вы ожидаете.

Если это не возвращает то, что вы ожидаете, это может быть связано с вашими собственными ошибками, но также может быть, что массив, хранящий ваши результаты, не сохраняет их правильно. Я сталкивался с делами раньше, чем мне приходилось переименовывать NSArray, потому что что-то о имени массива вызывало проблемы со ссылками, и поэтому массив не мог указать на ожидаемые результаты. Приветствия.

2

Добавьте это после того, как вы сохраните данные:

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

После нескольких часов отладки, я обнаружил, что причина моих обновления не были сохранены потому, что в моем подклассе NSManagedObject I определяется свойствами ж/@synthesize вместо @dynamic.

После того, как я его сменил, все было сохранено, как ожидалось.

Надеюсь, что кто-то помог.