Невозможно получить данные из базы данных Core Data sqlite - PullRequest
0 голосов
/ 25 апреля 2011

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

Ситуация: у меня есть приложение, в котором я использую предварительно заполненную базу данных sqlite (106 КБ) через Core Data. Я переместил sqlite DB в папку Resources и смог скопировать ее в документы. Когда я тестирую, я вижу, что файл существует, см. Пример кода и NSLog ниже.

Я использовал пример кода в делегате, см. Ниже.

Все отлично работает в симуляторе, но не при тестировании на устройстве.

Вот код от делегата:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
    return persistentStoreCoordinator_;
}


NSString *storePath = [[self applicationDocumentsDirectory]      stringByAppendingPathComponent: @"FamQuiz_R0_1.sqlite"];
/*
 Set up the store.
 For the sake of illustration, provide a pre-populated default store.
 */
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
    NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"FamQuiz_R0_1"      ofType:@"sqlite"];
    if (defaultStorePath) {
        [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
    }
}

NSURL *storeUrl = [NSURL fileURLWithPath:storePath];

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber   numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

NSError *error;
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
    // Update to handle the error appropriately.
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    exit(-1);  // Fail
}    

return persistentStoreCoordinator_;
}

Вот код, когда я читаю базу данных:

- (void)createQuestionsList: (NSMutableArray *)diffArray {
NSLog(@">>createQuestionsList<<");

NSFileManager *filemgr = [NSFileManager defaultManager];
NSString *docsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [docsDirectory stringByAppendingPathComponent:@"FamQuiz_R0_1.sqlite"];
if ([filemgr fileExistsAtPath: filePath ] == YES)
    NSLog (@"\n\n\nFile exists in createQuestionList\n\n\n");
else
    NSLog (@"\n\n\nFile not foundin createQuestionList\n\n\n");

int nrOfQuestions = [[diffArray objectAtIndex:0]intValue];
int nrOfEasyPlayers = [[diffArray objectAtIndex:1]intValue];
int nrOfMediumPlayers = [[diffArray objectAtIndex:2]intValue];
int nrOfHardPlayers = [[diffArray objectAtIndex:3]intValue];
int nrOfPlayers = nrOfEasyPlayers + nrOfMediumPlayers + nrOfHardPlayers;

allHardArrayQ = [[NSMutableArray alloc]init];
allMediumArrayQ = [[NSMutableArray alloc]init];
allEasyArrayQ = [[NSMutableArray alloc]init];
allDummyQ = [[NSMutableArray alloc]init];
allJointQ = [[NSMutableArray alloc]init];
hardQ = [[NSMutableArray alloc]init];
mediumQ = [[NSMutableArray alloc]init];
easyQ = [[NSMutableArray alloc]init];

masterQuestionsArray = [[NSMutableArray alloc] initWithObjects:
                        [NSNumber numberWithBool:[[diffArray objectAtIndex:4]boolValue]],
                        [NSNumber numberWithInt:nrOfHardPlayers],
                        [NSNumber numberWithInt:nrOfMediumPlayers],
                        [NSNumber numberWithInt:nrOfEasyPlayers],
                        [NSNumber numberWithInt:nrOfQuestions],
                        nil];
NSLog(@"masterQuestionsArray %@", masterQuestionsArray);

NSError *error;

//=========PREPARE CORE DATA DB===========//
if (managedObjectContext == nil) { managedObjectContext = [(FamQuiz_R0_1AppDelegate *)
                                                           [[UIApplication sharedApplication] delegate] managedObjectContext]; }

// Define qContext
NSManagedObjectContext *qContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription 
                               entityForName:@"questions" inManagedObjectContext:qContext];
[fetchRequest setEntity:entity];

NSArray *fetchedObjects = [qContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *info in fetchedObjects) {
    if ([[info valueForKey:@"qDiff"] intValue] == 1) { 
        [allEasyArrayQ addObject:[info valueForKey:@"idQ"]];
    } else if ([[info valueForKey:@"qDiff"] intValue] == 2) { 
        [allMediumArrayQ addObject:[info valueForKey:@"idQ"]];
    } else if ([[info valueForKey:@"qDiff"] intValue] == 3) { 
        [allHardArrayQ addObject:[info valueForKey:@"idQ"]];
    }
}

NSLog(@"allEasyArrayQ %@", allEasyArrayQ);
NSLog(@"allMediumArrayQ %@", allMediumArrayQ);
NSLog(@"allHardArrayQ %@", allHardArrayQ);

Вот вывод:

2011-04-25 19:35:45.008 FamQuiz_R0_1[963:307] >>createQuestionsList<<
2011-04-25 19:35:45.021 FamQuiz_R0_1[963:307] 


File exists in createQuestionList


2011-04-25 19:35:45.031 FamQuiz_R0_1[963:307] masterQuestionsArray (
1,
0,
0,
1,
5
)
2011-04-25 19:35:45.238 FamQuiz_R0_1[963:307] allEasyArrayQ (
)
2011-04-25 19:35:45.246 FamQuiz_R0_1[963:307] allMediumArrayQ (
)
2011-04-25 19:35:45.254 FamQuiz_R0_1[963:307] allHardArrayQ (
)
2011-04-25 19:35:45.311 FamQuiz_R0_1[963:307] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSMutableArray objectAtIndex:]: index 0 beyond bounds for empty array'

Я действительно ценю любую помощь, которую я могу получить, чтобы решить эту чрезвычайно неприятную проблему: -)

UPDATE

Я вставил NSLog в делегат, чтобы проверить storeURL, и получил следующий результат при работе на внешнем устройстве iPhone:

storeURL: file://localhost/var/mobile/Applications/7F5FDB03-0D22-46BC-91BC-4D268EB4BBEB/Documents/FamQuiz_R0_1.sqlite

При запуске в симуляторе без внешнего устройства iPhone:

storeURL: file://localhost/Users/PeterK/Library/Application%20Support/iPhone%20Simulator/4.2/Applications/E27EC1A4-3A87-4A1B-97DE-D464679005BE/Documents/FamQuiz_R0_1.sqlite

Ответы [ 3 ]

1 голос
/ 25 апреля 2011

Сбой, который вы получаете, не исходит из опубликованного кода.Последняя строка в коде:

NSLog(@"allHardArrayQ %@", allHardArrayQ);

... которая печатает.

Где-то ниже строки из предоставленного кода вы делаете вызов, подобный этому:

[someArray objectAtIndex:0]

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

Ваши массивы отображаются пустыми, потому что (1) вы не получаете возврата из своей выборки или (2) значения для qDiff и idQ не являются тем, что или где вы думаете, они есть.Чтобы подтвердить, добавьте журналы:

NSArray *fetchedObjects = [qContext executeFetchRequest:fetchRequest error:&error];
NSLog(@"fetchedObjects =",fetchedObjects);
for (NSManagedObject *info in fetchedObjects) {
    NSLog(@"[info valueForKey:@"qDiff"]",[info valueForKey:@"qDiff"]); 
    NSLog(@"[info valueForKey:@"idQ"]",[info valueForKey:@"idQ"]]);
    if ([[info valueForKey:@"qDiff"] intValue] == 1) { 
        [allEasyArrayQ addObject:[info valueForKey:@"idQ"]];
    ....

... которые хорошо сообщают вам, если вы получаете данные в первую очередь.Если нет, то вам нужно взглянуть на конфигурацию вашего стека основных данных.

В целом, я думаю, ваш код демонстрирует, что вы еще не совсем поняли базовые данные.Вместо этого вы, похоже, пытаетесь рассматривать Core Data как облегченную оболочку объекта для SQL.Это распространенное заблуждение среди специалистов по SQL, но плохо знакомых с Core Data, и это вызывает много проблем проектирования.

Во-первых, нет необходимости проверять физическое присутствие файла хранилища после инициализации постоянного хранилища.Объект NSPersistentStore в памяти не может существовать без файла хранилища, поэтому, если объект находится там, файл всегда там.

Во-вторых, вы накапливаете множество дополнительных структур данных в виде массивов.Это обычная необходимость при работе с необработанным SQL, но почти всегда она не нужна при использовании Core Data.Весь смысл Core Data заключается в том, чтобы управлять данными вручную (сохранение их на диск является просто опцией и не требуется.) Скорее всего, все ваши массивы должны быть объектами в модели данных, и вы должны использовать выборки и сортировки для извлеченияконкретные фрагменты данных, заказанные для неотложных потребностей любого конкретного представления.

Очень часто можно увидеть, как люди с сильным SQL или схожим опытом делают намного больше работы, чем необходимо для реализации Core Data.Это похоже на того, кто год за годом ездит на механической коробке передач и переключается на автомат.Они продолжают наступать на несуществующее сцепление и возятся с переключением передач.

0 голосов
/ 27 апреля 2011

ПРОБЛЕМА РЕШЕНА

Проведя еще один вечер, пытаясь отладить каждую строку кода, не понимая, я загрузил «iPhone Explorer» и вручную удалил два экземпляра БД напрямуюна устройстве и после этого оно наконец заработало.

Я заметил, что БД не была скопирована в папку документов, там находилась пустая БД, которая была меньше заполненной БД.

Теперь обаЭкземпляры БД правильные :-) ... это означает, что копия теперь работает.

Если вам нужен "iPhone Explorer", вы найдете его здесь: http://www.macroplant.com/iphoneexplorer/

0 голосов
/ 25 апреля 2011

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

//=========PREPARE CORE DATA DB===========//
if (managedObjectContext == nil) { managedObjectContext = [(FamQuiz_R0_1AppDelegate *)

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

Вы должны попробовать это шаг за шагом и быть уверенным, что ваши контекстные операции возвращают что-нибудь ... И немного очистите код, чтобы вам было легче увидеть проблему, или любому, кто пытается вам помочь ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...