在执行预准备语句之前,Sqlite objective c单例数据库连接关闭

时间:2013-08-04 12:37:31

标签: objective-c database sqlite connection singleton

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

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

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

[Database database];
db = [database getSqlite3Connection];
在我使用之前

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

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

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] DB CONNECTION - INTIALISING NEW  
     CONNECTION
2013-08-03 22:01:05.322 StoryboardTutorial[716:c07] *DB CONNECTION Address: 0x0
2013-08-03 22:01:05.328 StoryboardTutorial[716:c07] *DB CONNECTION getInstance:
2013-08-03 22:01:05.329 StoryboardTutorial[716:c07] DB CONNECTION INTIALISING NEW 
      CONNECTION
2013-08-03 22:01:05.330 StoryboardTutorial[716:c07] *DB CONNECTION Address: 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*Closing Connection
2013-08-03 22:01:05.331 StoryboardTutorial[716:c07]     WordsList:getWordforId: 
    Problem with prepare statement

1 个答案:

答案 0 :(得分:0)

你说你添加了一行:

dbConnection = (__bridge sqlite3 *)(database);

,因为

  

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

我不明白你的意图。

  • 在Objective-C和Core Foundation之间转移指针时,只使用__bridge而不转让所有权;但SQLite与Core Foundation无关;

  • 即使它是,databaseDatabase对象,它与sqlite3指针完全不同;

  • 更糟糕的是,在打开数据库并设置dbConnection指针后,您就拥有了这一行代码,因此您实际上已经放弃了对刚刚打开的数据库的唯一引用

    < / LI>

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

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指针,就使用那个方法,你应该很好。