我在iOS中使用sqlite数据库。我在我的应用程序中使用了CURD操作。例如,将数据插入我使用下面代码的数据库。
- (BOOL) saveData:(User *)user
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
if([self getUserData:user.email] != nil)
{
[self updateUserData:user];
return YES;
}
else
{
NSString *insertSQL = [NSString stringWithFormat:
@"insert into users(userid,name,email,password,address,age,gender,phone,qualification,role,createddate,apiKey,priorityid,usertype) values (\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\",\"%@\")",user.userid,user.name,user.email,user.password,user.address,user.age,user.gender,user.phone,user.qualification,user.role,user.createddate,user.api_key,user.priority_id,user.user_type];
NSLog(@"%@",insertSQL);
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
sqlite3_finalize(statement);
// sqlite3_close(database);
return YES;
}
else
{
NSLog(@"%serrr is ",sqlite3_errmsg(database));
//sqlite3_reset(statement);
sqlite3_close(database);
return NO;
}
}
}
//sqlite3_reset(statement);
sqlite3_close(database);
return NO;
}
由于sqlite数据库,我的应用程序出现内存问题。我无法理解调用 sqlite3_reset(); , sqlite3_finalize()的顺序, sqlite3_close()。请告诉我的代码,以便我可以解决我的应用中的所有内存问题
修改
- (BOOL) insertSeMapData:(Client *)client : (NSString *)userid : (NSString *)sendemailto : (NSString *)assignworkordersto
{
BOOL result=NO;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
InspectionMapDetails *inspMap = [self getSEMapData:client :userid];
if(inspMap != nil)
{
[self updateSEMapData:client :userid :inspMap : sendemailto : assignworkordersto];
result=YES;
}
else
{
const char *insert_stmt = "insert into map(inspid,inspectorid,clientid,status,createddate,sendemailreportto,assignworkordersto) values (?,?,?,?, datetime(),?,?)";
if (sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL) == SQLITE_OK)
{
NSString *clientinspid=[NSString stringWithFormat:@"%@",client.inspid];
NSString *clientid=[NSString stringWithFormat:@"%@",client.clientid];
userid=[NSString stringWithFormat:@"%@",userid];
sqlite3_bind_text(statement, 1, [clientinspid UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 2, [userid UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 3, [clientid UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 4, [sendemailto UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(statement, 5, [assignworkordersto UTF8String], -1, SQLITE_TRANSIENT);
if (sqlite3_step(statement) == SQLITE_DONE)
{
result = YES;
}
sqlite3_finalize(statement);
}
else
{
NSLog(@"Unable to prepare statement: %s",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
}
else
{
NSLog(@"Unable to open database: %s",sqlite3_errmsg(database));
}
return result;
}
以上功能导致内存问题。这里 Sqlite_open 语句导致内存泄漏,我不明白为什么?
答案 0 :(得分:8)
有简单的指导方针,而且直言不讳,你的代码根本不会遵循它们。
每次成功拨打sqlite3_open
,您都必须拨打sqlite3_close
。
每次成功拨打sqlite3_prepare_v2
,您都必须致电sqlite3_finalize
。 (可选)在您重复使用预准备语句的情况下,您可以在两者之间调用sqlite3_reset
。
您应该始终查看对sqlite3_open
和sqlite3_prepare_v2
的来电结果。如果它们失败,您应该使用sqlite3_errmsg
来记录问题所在。
不要使用stringWithFormat
构建查询字符串。相反,使用对各种sqlite3_bind_xxx
函数的适当调用将值正确绑定到查询。
您发布的代码违反了所有这些规定。在很多情况下,您不会关闭数据库或完成准备好的语句。而且您使用stringWithFormat:
错误地构建了查询。
这里的代码全部修好了。请注意,我假设您插入的所有值都是字符串。相应地调整任何非字符串值。
- (BOOL) saveData:(User *)user
{
BOOL result = NO;
if([self getUserData:user.email] != nil)
{
[self updateUserData:user];
result = YES;
}
else
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &database) == SQLITE_OK)
{
const char *insert_stmt = "insert into users(userid,name,email,password,address,age,gender,phone,qualification,role,createddate,apiKey,priorityid,usertype) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
if (sqlite3_prepare_v2(database, insert_stmt,-1, &statement, NULL) == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, [user.userid UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, [user.name UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, [user.email UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 4, [user.password UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 5, [user.address UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 6, [user.age UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 7, [user.gender UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 8, [user.phone UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 9, [user.qualification UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 10, [user.role UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 11, [user.createddate UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 12, [user.api_key UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 13, [user.priority_id UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 14, [user.user_type UTF8String], -1, SQLITE_TRANSIENT);
if (sqlite3_step(statement) == SQLITE_DONE)
{
result = YES;
}
sqlite3_finalize(statement);
}
else
{
NSLog(@"Unable to prepare statement: %s",sqlite3_errmsg(database));
}
sqlite3_close(database);
}
else
{
NSLog(@"Unable to open database: %s",sqlite3_errmsg(database));
}
}
return result;
}
根据新修改进行更新:
就像您的原始代码一样,您违反了一些规则。您更新的代码并不完全符合我在上面的答案中给出的模式。
现在的主要问题是您打开数据库,但只能在两个可能的代码路径之一下关闭它。如果inspMap != nil
,您永远不会关闭数据库。
您真的应该重构代码,以便在inspMap
为nil
时才打开数据库。我在原始答案中做了类似于原始代码的事情。