iOS SQLite Blob 数据正在保存 NULL
iOS SQLite Blob data is saving NULL
我正在尝试使用此代码插入 SignatureView 的 BLOB 数据,但是当我实际浏览数据库时,出现的是 null 而不是数据。
我的签名 table 架构如下。
create table sign(id integer primary key AUTOINCREMENT, image blob,invoiceid integer);
-(void)storeImageData:(NSData *)imageData withInvoiceID:(NSInteger)invoiceID{
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:@"database.sqlite3"];
const char *dbpath = [dbPath UTF8String];
sqlite3 *contactDB;
sqlite3_stmt *statement;
NSLog(@"%@",dbPath);
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
int invoiceIDINT = (int)invoiceID;
//
NSString *insertSQL = [NSString stringWithFormat: @"INSERT INTO sign (image,invoiceid) VALUES (?,%d)", invoiceIDINT];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
sqlite3_bind_blob(statement, 2, [imageData bytes], [imageData length], SQLITE_TRANSIENT);
sqlite3_step(statement);
} else {
const char *Error = sqlite3_errmsg(database);
NSString *error = [[NSString alloc]initWithUTF8String:Error];
UIAlertView *view = [[UIAlertView alloc]initWithTitle:@"Error2" message:[NSString stringWithFormat:@"Last inserted ID: %@",error] delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:nil, nil];
[view show];
}
sqlite3_finalize(statement);
sqlite3_close(contactDB);
}
}
- 始终检查
sqlite3_prepare_v2
的结果。如果失败,请使用 sqlite3_errmsg
. 记录问题
- 仅在
sqlite3_prepare_v2
成功时才调用 sqlite3_finalize
。
- Blob 得到
NULL
,因为对 sqlite3_bind_blob
的调用传递了错误的列索引。它应该是 1
,而不是 2
,因为您想绑定到 INSERT
语句中的第一个 ?
。
- 为什么不一致?为什么使用
stringWithFormat
设置 invoiceid
列的值,然后使用 sqlite_bind_xxx
设置 image
列的值?你应该绑定两者。切勿使用 stringWithFormat
构建查询。
- 您调用
sqlite3_step
两次。只调用一次并在调用前绑定您的值。
- 您似乎正在写入应用程序资源包内的数据库。你不能在真实设备上这样做。它适用于模拟器,但不适用于真正的 iOS 设备。您需要将数据库文件放在 Documents 文件夹中。
考虑到以上所有内容,您的代码应该是这样的:
-(void)storeImageData:(NSData *)imageData withInvoiceID:(NSInteger)invoiceID{
// This is wrong - you need to update this to use the Documents folder
NSString *dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"database.sqlite3"];
const char *dbpath = [dbPath UTF8String];
NSLog(@"%@",dbPath);
sqlite3 *contactDB;
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
const char *insert_stmt = "INSERT INTO sign (image, invoiceid) VALUES (?, ?)";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL) == SQLITE_OK) {
sqlite3_bind_blob(statement, 1, [imageData bytes], [imageData length], SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 2, (int)invoiceID);
if (sqlite3_step(statement) == SQLITE_DONE) {
// Row inserted successfully
} else {
const char *Error = sqlite3_errmsg(contactDB);
NSString *error = [[NSString alloc] initWithUTF8String:Error];
UIAlertView *view = [[UIAlertView alloc] initWithTitle:@"Error2" message:[NSString stringWithFormat:@"Last inserted ID: %@",error] delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:nil, nil];
[view show];
}
sqlite3_finalize(statement);
} else {
NSLog(@"Unable to prepare statement %s: %s", insert_stmt, sqlite3_errmsg(contactDB));
}
sqlite3_close(contactDB);
} else {
NSLog(@"Unable to open database at path %@: %s", dbPath, sqlite3_errmsg(contactDB));
}
}
我正在尝试使用此代码插入 SignatureView 的 BLOB 数据,但是当我实际浏览数据库时,出现的是 null 而不是数据。 我的签名 table 架构如下。
create table sign(id integer primary key AUTOINCREMENT, image blob,invoiceid integer);
-(void)storeImageData:(NSData *)imageData withInvoiceID:(NSInteger)invoiceID{
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:@"database.sqlite3"];
const char *dbpath = [dbPath UTF8String];
sqlite3 *contactDB;
sqlite3_stmt *statement;
NSLog(@"%@",dbPath);
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
int invoiceIDINT = (int)invoiceID;
//
NSString *insertSQL = [NSString stringWithFormat: @"INSERT INTO sign (image,invoiceid) VALUES (?,%d)", invoiceIDINT];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
sqlite3_bind_blob(statement, 2, [imageData bytes], [imageData length], SQLITE_TRANSIENT);
sqlite3_step(statement);
} else {
const char *Error = sqlite3_errmsg(database);
NSString *error = [[NSString alloc]initWithUTF8String:Error];
UIAlertView *view = [[UIAlertView alloc]initWithTitle:@"Error2" message:[NSString stringWithFormat:@"Last inserted ID: %@",error] delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:nil, nil];
[view show];
}
sqlite3_finalize(statement);
sqlite3_close(contactDB);
}
}
- 始终检查
sqlite3_prepare_v2
的结果。如果失败,请使用sqlite3_errmsg
. 记录问题
- 仅在
sqlite3_prepare_v2
成功时才调用sqlite3_finalize
。 - Blob 得到
NULL
,因为对sqlite3_bind_blob
的调用传递了错误的列索引。它应该是1
,而不是2
,因为您想绑定到INSERT
语句中的第一个?
。 - 为什么不一致?为什么使用
stringWithFormat
设置invoiceid
列的值,然后使用sqlite_bind_xxx
设置image
列的值?你应该绑定两者。切勿使用stringWithFormat
构建查询。 - 您调用
sqlite3_step
两次。只调用一次并在调用前绑定您的值。 - 您似乎正在写入应用程序资源包内的数据库。你不能在真实设备上这样做。它适用于模拟器,但不适用于真正的 iOS 设备。您需要将数据库文件放在 Documents 文件夹中。
考虑到以上所有内容,您的代码应该是这样的:
-(void)storeImageData:(NSData *)imageData withInvoiceID:(NSInteger)invoiceID{
// This is wrong - you need to update this to use the Documents folder
NSString *dbPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"database.sqlite3"];
const char *dbpath = [dbPath UTF8String];
NSLog(@"%@",dbPath);
sqlite3 *contactDB;
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
const char *insert_stmt = "INSERT INTO sign (image, invoiceid) VALUES (?, ?)";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL) == SQLITE_OK) {
sqlite3_bind_blob(statement, 1, [imageData bytes], [imageData length], SQLITE_TRANSIENT);
sqlite3_bind_int(statement, 2, (int)invoiceID);
if (sqlite3_step(statement) == SQLITE_DONE) {
// Row inserted successfully
} else {
const char *Error = sqlite3_errmsg(contactDB);
NSString *error = [[NSString alloc] initWithUTF8String:Error];
UIAlertView *view = [[UIAlertView alloc] initWithTitle:@"Error2" message:[NSString stringWithFormat:@"Last inserted ID: %@",error] delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:nil, nil];
[view show];
}
sqlite3_finalize(statement);
} else {
NSLog(@"Unable to prepare statement %s: %s", insert_stmt, sqlite3_errmsg(contactDB));
}
sqlite3_close(contactDB);
} else {
NSLog(@"Unable to open database at path %@: %s", dbPath, sqlite3_errmsg(contactDB));
}
}