无法从Core Data sqlite DB获取数据

时间:2011-04-25 17:40:16

标签: iphone objective-c core-data sqlite

首先,我想就这个问题启动多个线程而道歉但我采取了逐步的方法和步骤来解决这个非常恼人的问题。我现在花了四天时间试图解决这个问题。

情况:我有一个应用程序,我通过Core Data使用预先填充的sqlite数据库(106k)。我已将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'

我真的非常感谢所有帮助,我可以解决这个非常令人沮丧的问题: - )

更新

我确实在代理中放入了一个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 个答案:

答案 0 :(得分:1)

您获得的崩溃不是来自发布的代码。代码中的最后一行是:

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

...打印。

在提供的代码的某处,你可以这样打电话:

[someArray objectAtIndex:0]

...虽然someArray为空,但会导致超出范围错误。最有可能的是,someArray是刚刚记录但未必记录的三个空数组之一。

您的数组显示为空,因为(1)您的获取未获得任何回复或(2)qDiffidQ的值不是您认为的或您认为的位置。要确认,请添加日志:

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堆栈的配置。

更一般地说,我认为您的代码表明您尚未在概念上掌握Core Data。相反,您似乎正在尝试将Core Data视为SQL的轻量级对象包装器。这是SQL技术人员常见的误解,但对核心数据来说是新的,它会导致很多设计问题。

首先,在初始化持久性存储之后,没有理由检查存储文件的物理存在。没有存储文件,内存中的NSPersistentStore对象不能存在,因此如果对象存在,则文件始终存在。

其次,您正在以数组的形式堆积许多其他数据结构。这是处理原始SQL时的常见需求,但在使用Core Data时几乎总是不必要的。 Core Data的全部内容是手动管理数据(将其保存到磁盘只是一个选项而不是必需的。)所有数组都应该是数据模型中的实体,您应该使用提取和排序来提取为特定视图的直接需求而订购的特定数据。

通常情况下,看到具有强大SQL或类似背景的人会这样做,比实现核心数据所需的工作量更多。就像有人一年驾驶手动变速器切换到自动变速箱的人。他们继续踩着不存在的离合器,摆弄换档。

答案 1 :(得分:0)

好像你没有从上下文中得到任何东西,所有三个数组都是空的。这个例外似乎是从你在这里粘贴的东西中抛出的。坦率地说,有一些不相关的冗余部分,比如;

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

...从未使用过,但主要的问题是我想,你正试图访问一个空数组,假设有来自上下文的东西,但显然不是......

你应该一步一步地尝试,并确保你的上下文操作返回任何东西...... 并清理一下代码,以便您可以更轻松地查看问题,或者任何想要帮助您的人......

答案 2 :(得分:0)

问题已解决

在又花了一个晚上试图调试代码中的每一行之后,我没有理解,我下载了“iPhone Explorer”并直接在设备上手动删除了DB的两个实例,之后终于工作了。

我注意到数据库没有复制到文档文件夹,有一个空的DB,它比填充的DB小。

现在两个数据库实例都是正确的:-) ...意味着副本现在可以正常工作。

如果你想要“iPhone Explorer”,你可以在这里找到它:http://www.macroplant.com/iphoneexplorer/