无法从 Core Data sqlite DB 获取数据

发布于 2024-11-03 03:44:02 字数 6064 浏览 0 评论 0原文

首先,我想为针对这个问题启动多个线程表示歉意,但我已经采取了逐步的方法和步骤来解决这个非常恼人的问题。我已经花了四天的时间来尝试解决这个问题。

情况:我有一个应用程序,我通过 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

First i want to apologize for starting more than one thread about this problem but i have taken step-by-step approach and steps to solve this very irritating problem. I have spend four days now to try to solve this.

The situation: I have an application where i use a pre-populated sqlite database (106k), via Core Data. I have moved the sqlite DB to the Resources folder and being able to copy it into documents. When i test i can see that the file exist, see code example and NSLog below.

I have used example code in the delegate, see below.

Everything works perfectly in the simulator but not when i test on the device.

Here is the code from the delegate:

- (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_;
}

Here is the code when i read the database:

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

Here is the output:

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'

I REALLY appreciate all help i can get to solve this extremely frustrating problem :-)

UPDATE

I did put in a NSLog in the delegate to check the storeURL and got the following result when running on the external iPhone device:

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

The following is when i run in the simulator, without the external iPhone device:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

逆光飞翔i 2024-11-10 03:44:02

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

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

... 打印。

在所提供的代码中的某个位置,您可以进行如下调用:

[someArray objectAtIndex:0]

... while 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 视为围绕 SQL 的轻量级对象包装器。对于熟悉 SQL 但刚接触 Core Data 的人来说,这是一个常见的误解,它会导致很多设计问题。

首先,在初始化持久存储后,没有理由检查存储文件的物理存在。如果没有存储文件,内存中的 NSPercientStore 对象就无法存在,因此如果该对象存在,则该文件始终存在。

其次,您以数组的形式堆积了大量额外的数据结构。这是处理原始 SQL 时的常见需求,但在使用 Core Data 时几乎总是不必要的。核心数据的全部要点是手动管理数据(将其保存到磁盘只是一个选项,而不是必需的。)所有数组很可能都是数据模型中的实体,并且您应该使用获取和排序来提取数据为满足任何特定视图的直接需求而排序的特定数据。

很常见的是,具有强大 SQL 或类似背景的人做的工作比实现核心数据所需的工作多得多。这就像驾驶手动变速箱一年的人切换到自动变速箱一样。他们不断地踩着不存在的离合器并摆弄变速杆。

The crash you are getting is not coming from the posted code. The last line in the code is:

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

... which prints.

Somewhere down the line from the provided code you make a call like this:

[someArray objectAtIndex:0]

... while someArray is empty and that causes the out of range error. Most likely, someArray is one of the three empty arrays just logged but not necessarily.

Your arrays are showing empty because (1) you are getting no returns from your fetch or (2) the values for qDiff and idQ aren't what or where you think they are. To confirm, add logs:

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"]];
    ....

... that well tell you if you are getting the data in the first place. If not then you need to look at the configuration of your Core Data stack.

More generally, I think your code demonstrates that you haven't quite conceptually grasped Core Data yet. Instead, you seem to being trying to treat Core Data as a lightweight object wrapper around SQL. This is a common misperception among those skilled at SQL but new to Core Data and it causes a lot of design issues.

Firstly, there is no reason to check for the physical presence of the store file after you have initialize the persistent store. The NSPersistentStore object in memory cannot exist without the store file so if the object is there, the file is always there.

Secondly, you are piling on a lot of additional data structures in the form of arrays. This is a common need when dealing with raw SQL but is almost always unnecessary when using Core Data. The entire point of Core Data is to manage data manually (persisting it to the disk is just an option and is not required.) All your arrays should most likely be entities in the data model and you should be using fetches and sorts to pull out specific pieces of data ordered for the immediate needs of any particular view.

It's very common to see people with a strong SQL or similar background doing way, way more work than needed to implement Core Data. It's like someone who has drive a manual transmission for year who switches to an automatic. They keep stepping on the non-existent clutch and fiddling with the gear shift.

君勿笑 2024-11-10 03:44:02

似乎您没有从上下文中获取任何内容,所有三个数组都打印为空。异常似乎是从您粘贴到此处的内容中抛出的。坦率地说,有一些不相关的、多余的部分,比如;

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

...从未使用过,但主要问题是我猜,您正在尝试访问一个空数组,假设上下文中存在某些内容,但显然不是...

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

Seems like you are not getting anything from the context, all three arrays are printed empty. And the exception seems to be thrown from out of what you ve pasted here. Frankly, there are irrelevant, redundant parts like;

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

...which is never used, but the main problem is i guess, you are trying to access an empty array assuming something from the context comes in there, but apparently not...

You should try it step by step and be sure that your context operations return anything...
And clean the code a bit so that you can see the problem easier, or anyone who is trying to help you...

三岁铭 2024-11-10 03:44:02

问题已解决

又花了一个晚上尝试调试代码中的每一行,但在不理解的情况下,我下载了“iPhone Explorer”并直接在设备上手动删除了数据库的两个实例,之后它终于工作了。

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

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

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

PROBLEM SOLVED

After spending yet another evening trying to debug every line in the code, without understanding, i downloaded "iPhone Explorer" and manually deleted the two instances of the DB directly on the device and after that it finally worked.

I noticed that the DB was not copied to the documents folder, there an empty DB resided that was smaller that the populated DB.

Now both DB instances is the correct ones :-) ...meaning that copy works now.

If you want the "iPhone Explorer" you will find it here: http://www.macroplant.com/iphoneexplorer/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文