目标c中的简单sqlite3_prepare问题

时间:2014-10-16 20:01:58

标签: objective-c sqlite

我已经在线阅读了各种关于在ios中处理sqlite3数据库的教程,特别是我已经阅读过" Ray Wenderlich"教程和阅读这里的许多查询,但我不明白为什么我的代码不起作用。

我有一个看似打开的简单数据库。它有一个包含200个多项选择题的表格。我试图选择所有答案,查询并不复杂,并且可以在sqlitebrowser中使用。

我也已将libsqlite3.dylib添加到项目中,否则数据库的打开将无法正常工作。我确信这是一个非常简单的修复方法,但在查看代码后我无法看到它:

@implementation QuizController
sqlite3 *db;

- (void)viewDidLoad {
  [super viewDidLoad];
  NSLog(@"Hello Quiz");

  NSString *p = [self filePath];
  [self openDB];
  NSString *query = @"SELECT answer from questions";

  sqlite3_stmt *statement;

  if (sqlite3_prepare_v2(db, [query UTF8String], -1, &statement, NULL)
    == SQLITE_OK) {

    NSLog(@"SQLITE PREPARED OK!");
    while (sqlite3_step(statement) == SQLITE_ROW) {

        NSLog(@"YES");

    }
  }
  else{
    NSLog(@"sqlite prepare failed");
  }


}


//file path to db
-(NSString *) filePath {
  NSLog(@"pathtest");
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  return [[paths objectAtIndex:0] stringByAppendingPathComponent:@"questionsDb.sqlite"];
}

//open the db
-(void)openDB {
  NSLog(@"opentest");
  if (sqlite3_open([[self filePath] UTF8String], &db) !=SQLITE_OK) {
    NSLog(@"%d", sqlite3_open([[self filePath] UTF8String], &db));
    sqlite3_close(db);
    NSLog(@"Database failed to open");
  } else {
    NSLog(@"database opened");
  }
}

我看到的日志输出是:

2014-10-16 20:52:01.627 QuizTemplate[15963:802498] pathtest
2014-10-16 20:52:01.627 QuizTemplate[15963:802498] opentest
2014-10-16 20:52:01.628 QuizTemplate[15963:802498] pathtest
2014-10-16 20:52:01.648 QuizTemplate[15963:802498] database opened
2014-10-16 20:52:01.649 QuizTemplate[15963:802498] sqlite prepare failed

1 个答案:

答案 0 :(得分:1)

更改您的" sqlite准备失败"包括sqlite3_errmsg

NSLog(@"sqlite prepare failed: %s", sqlite3_errmsg(db));

毫无疑问,它会告诉你表格不存在。

这是因为您的打开例程只是打开文档文件夹中的数据库,如果不存在,则会创建一个空白数据库。 (如果找不到文件,那就是sqlite3_open的作用。)

你可能想要:

  1. 从您的设备/模拟器中卸载应用程序,以删除可能存在的任何空白数据库。

  2. 您想要调用将在文档中查找数据库的例程,如果找不到,请将其从包中复制到Documents:

    - (void) installDatabaseIfNeeded {
    
        // Get the documents database path
    
        NSString *documentsFolder = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
        NSString *documentsDatabasePath = [documentsFolder stringByAppendingPathComponent:@"test.sqlite"]; // always use setter when setting property's value
    
        NSFileManager *fileManager = [NSFileManager defaultManager];
    
        if (![fileManager fileExistsAtPath:documentsDatabasePath]) {
    
            // if the database doesn't exist in documents, look for it in the bundle and copy it if found
    
            NSString *bundleDatabasePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"sqlite"];
    
            if (bundleDatabasePath) {
                NSError *error;
                if (![fileManager copyItemAtPath:bundleDatabasePath toPath:documentsDatabasePath error:&error]) {
                    NSLog(@"copyItemAtPath failed: %@", error);
                }
            }
        }
    }
    

    显然,请更改bundleDatabasePathdocumentsDatabasePath中引用的文件名,但希望这说明了这一概念。


  3. 如果您仍然遇到问题,还有一些额外的想法:

    1. 使用sqlite3_open选项将sqlite3_open_v2的所有来电替换为SQLITE_OPEN_READWRITE。如果我们省略SQLITE_OPEN_CREATE选项,如果它找不到它,显然不会创建空白数据库。让我们消除这种可能性。因此:

      - (void)openDB {
          NSLog(@"opentest");
          int rc = sqlite3_open_v2([[self filePath] UTF8String], &db, SQLITE_OPEN_READWRITE, NULL);
          if (rc != SQLITE_OK) {
              NSLog(@"open failed: %d", rc);
              NSLog(@"Database failed to open");
          } else {
              NSLog(@"database opened");
          }
      }
      
    2. 再次删除该应用并重新安装。 (不要只是做一个"干净的构建",但实际上是从设备/模拟器中删除应用程序。)

    3. 构建应用程序并将其安装在模拟器上。现在检查包中的数据库:

      • 打开模拟器的设备文件夹;

      • 在Mac OS文件系统中找到您的应用(位于Xcode 6之前的Xcode版本~/Library/Application Support/iPhone Simulator下方,Xcode 6中为~/Library/Developer/CoreSimulator/Devices);

      • 打开应用程序包(右键单击它并选择"显示包内容");

      • 在捆绑中查找数据库副本;以及

      • 在您选择的数据库工具中打开它。确保您的表实际存在于数据库的副本中,并且名称是正确的。

      有时,Xcode会对包中的内容(特别是使用外部编辑的文件,如SQLite数据库)感到困惑,这可以通过删除派生数据文件夹来解决。或者您可能拥有数据库的多个副本,而忽略了更新Xcode项目中的数据库。

      这可能是很多事情,所以通过检查捆绑中的真实内容,它将确定问题的根源。