0

Sqlite3 目标 c 单例数据库连接在执行准备好的语句之前关闭我在目标 c 中创建了一个单例数据库连接,但它在执行准备好的语句之前关闭。

我来自 java 背景,这是我的第一个 xcode 项目。使用 xcode 4.5.2。我只想建立一个所有文件都可以使用的数据库连接。我查看了许多有关该主题的留言板,并花了难以置信的时间试图解决它,我似乎无法解决这个问题。如果有人能解释在执行准备好的语句之前我需要做什么才能使 sql 连接不关闭,我将不胜感激。我在下面包含了代码和运行时输出。

我制作了一个数据库单例并在 appDelegate 中成功初始化它。然后在我需要连接的类中,我指的是这样的数据库连接:

[Database database];
db = [database getSqlite3Connection];

在我使用之前:

AppDelegate *appDelegate =  (AppDelegate *)[[UIApplication sharedApplication] 
    delegate];
db = [appDelegate db];

在这两种情况下,代码都会运行但无法执行准备好的语句。但是,当我将创建数据库连接代码放入需要使用连接的类时,连接执行准备好的语句没有问题:即:

NSString *dbPath = [[[NSBundle mainBundle] resourcePath]                     
                     stringByAppendingPathComponent:@"hsk1.sqlite"];
if (sqlite3_open([dbPath UTF8String], &dbConnection) != SQLITE_OK)

我对这些类如何接收全局 sqlite3 连接感到困惑。有人可以告诉这是否是正确的方法:

在我的数据库类中,我使用此代码将我创建的数据库对象传递给 sqlite3,因此我可以将它用于我所有类的准备语句:

sqlite3 *dbConnection = (__bridge sqlite3 *)(database);

我的代码:

//  AppDelegate.h
//  StoryboardTutorial

#import <UIKit/UIKit.h>
#import "Database.h"
#import <sqlite3.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic,readonly) Database *database;
@property (nonatomic,readonly) sqlite3 *db;

@end

//  AppDelegate.m
//  StoryboardTutorial
#import "AppDelegate.h"
@implementation AppDelegate
@synthesize database;
@synthesize db;
@synthesize window = _window;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    [Database database];
    db = [database getSqlite3Connection];

    return YES;
}

//  Database.h
#import <Foundation/Foundation.h>
#import <sqlite3.h>

@interface Database : NSObject {
}
+ (Database *)database;
- (id)init;
+ (Database *)getInstance;
-(sqlite3 *)getSqlite3Connection;
- (void)dealloc;
@end

//
//  database.m
//
#import "Database.h"

@implementation Database

static Database *database;

sqlite3 *dbConnection =nil;

+ (Database*)database {
    if (database == nil) {
        database = [[Database alloc] init];
    }
    return database;
}

- (id)init{
    if (self = [super init]) {

        NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]
                            stringByAppendingPathComponent:@"hsk1.sqlite"];
        NSLog(@"DB CONNECTION - INTIALISING NEW CONNECTION");
        if (sqlite3_open([dbPath UTF8String], &dbConnection) != SQLITE_OK) {

            NSLog(@"[SQLITE] Unable to open database!");
            return nil; // if it fails, return nil obj
        }
        dbConnection = (__bridge sqlite3 *)(database);

        NSLog(@"*DB CONNECTION Address: %p", database);
    }
    return self;
}

+(Database *)getInstance {
    @synchronized(self)
    {
        NSLog(@"*DB CONNECTION getInstance:");
        if (database == nil){
            NSLog(@"DB CONNECTION - none");
            database = [[self alloc] init];
            NSLog(@"DB CONNECTION getInstance() Address: %p", database);
        }
    }
    return(database);
}

-(sqlite3*)getSqlite3Connection {
    return dbConnection;
}

- (void)dealloc {
    NSLog(@"DB CONNECTION*Closing Connection");
    sqlite3_close(dbConnection);
}

@end

//  ViewController.h
//

#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>

@interface ViewController : UIViewController<UITableViewDelegate,
UITableViewDataSource,  AVAudioPlayerDelegate>{
    AVAudioPlayer *audioPlayer;
}
@property(nonatomic, retain)NSMutableArray *wordListsArray;
@end

//  ViewController.m
//

#import "ViewController.h"
#import "WordLists.h"
#import "Database.h"
#import "AppDelegate.h"

@implementation ViewController

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

    int wordid =1;

    WordLists * mywords =[[WordLists alloc] init];

    self.wordListsArray = [mywords getWordforId:(NSInteger)wordid];
}

//  WordLists.h
//

#import <Foundation/Foundation.h>

@interface WordLists : NSObject{
}
- (NSMutableArray *) getWordforId :(NSInteger)wordid;
@end

//  WordLists.m
//

#import "AppDelegate.h"
#import "WordLists.h"
#import "Word.h"
#import "Database.h"

@implementation WordLists
Database *database =nil;
sqlite3 *db = nil;

- (id)init {
    Database *database  = [Database getInstance];
    db = [database getSqlite3Connection];

    if (db == nil) {
        database = [[Database alloc] init];
        NSLog(@"**Wordlists:init: db is nil");
    }
    return self;
}

- (NSMutableArray *) getWordforId :(NSInteger)wid{

    int wordid = wid;
    sqlite3_stmt *sqlStatement;

    NSMutableArray *WordArray = [[NSMutableArray alloc] init];
    @try {

        const char *sql = "SELECT id,ename,pname,hname,hsound FROM words WHERE id=?";

        if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
        {
            NSLog(@"WordsList:getWordforId: Problem with prepare statement");
        }

        sqlite3_bind_int(sqlStatement,1, wordid);

        while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
            NSLog(@"MyWords:getMyWords: Record numbers");

            Word *MyWord = [[Word alloc]init];
            MyWord.wordId = sqlite3_column_int(sqlStatement, 0);
            MyWord.ename = [NSString stringWithUTF8String:(char *)
                            sqlite3_column_text(sqlStatement,1)];
            MyWord.pname = [NSString stringWithUTF8String:(char *)
                            sqlite3_column_text(sqlStatement, 2)];
            MyWord.hname = [NSString stringWithUTF8String:(char *)
                            sqlite3_column_text(sqlStatement, 3)];
            MyWord.hsound = [NSString stringWithUTF8String:(char *)
                             sqlite3_column_text(sqlStatement, 4)];
            [WordArray addObject:MyWord];

            NSLog(@"wineId : %d", MyWord.wordId);
        }
        sqlite3_reset(sqlStatement);
        sqlite3_finalize(sqlStatement);

        return WordArray;
    }@catch (NSException *exception) {
        NSLog(@"An exception occured: %@", [exception reason]);
    }
    @finally {

    }
}
@end

运行时输出:

2013-08-03 22:01:05.320 StoryboardTutorial[716:c07] 数据库连接 - 初始化新  
     联系
2013-08-03 22:01:05.322 StoryboardTutorial[716:c07] *DB 连接地址:0x0
2013-08-03 22:01:05.328 StoryboardTutorial[716:c07] *DB CONNECTION getInstance:
2013-08-03 22:01:05.329 StoryboardTutorial[716:c07] 数据库连接初始化新
      联系
2013-08-03 22:01:05.330 StoryboardTutorial[716:c07] *DB 连接地址:0x7d78ea0
2013-08-03 22:01:05.330 StoryboardTutorial[716:c07] **Wordlists:init: db is nil
2013-08-03 22:01:05.331 StoryboardTutorial[716:c07] DB CONNECTION*关闭连接
2013-08-03 22:01:05.331 StoryboardTutorial[716:c07] WordsList:getWordforId:
    准备语句的问题
4

1 回答 1

0

您说您添加了以下行:

dbConnection = (__bridge sqlite3 *)(database);

因为

在我的数据库类中,我使用此代码将我创建的数据库对象传递给 sqlite3,因此我可以将它用于我所有类的准备语句:

我不明白你的意图。

  • 您仅__bridge在没有所有权转移的情况下在 Objective-C 和 Core Foundation 之间传输指针时使用;但 SQLite 与 Core Foundation 无关;

  • 即使是,database也是一个对象,它与指针Database完全不同;sqlite3

  • 更糟糕的是,您在打开数据库并设置dbConnection指针后立即拥有那行代码,因此您有效地丢弃了对刚刚打开的数据库的唯一引用

简而言之,您应该删除该行,从而转换:

if (sqlite3_open([dbPath UTF8String], &dbConnection) != SQLITE_OK) {

    NSLog(@"[SQLITE] Unable to open database!");
    return nil; // if it fails, return nil obj
}
dbConnection = (__bridge sqlite3 *)(database);

NSLog(@"*DB CONNECTION Address: %p", database);

至:

if (sqlite3_open([dbPath UTF8String], &dbConnection) != SQLITE_OK) {

    NSLog(@"[SQLITE] Unable to open database!");
    return nil; // if it fails, return nil obj
}
NSLog(@"*DB CONNECTION Address: %p", dbConnection);

回到我们刚刚添加的那一行的意图,您已经定义了一个getSqlite3Connection实现该目标的方法。因此,只要您需要sqlite3指针,请使用该方法,您应该会很好。

于 2013-08-04T14:56:32.920 回答