在执行预准备语句之前,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
答案 0 :(得分:0)
你说你添加了一行:
dbConnection = (__bridge sqlite3 *)(database);
,因为
在我的数据库类中,我使用此代码将我创建的数据库对象传递给sqlite3,因此我可以将它用于我所有类的预编译语句:
我不明白你的意图。
在Objective-C和Core Foundation之间转移指针时,只使用__bridge
而不转让所有权;但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
指针,就使用那个方法,你应该很好。