Ios 用于swift的sqlite不稳定
我已经建立了使用sqlite的swift项目。有时,当插入时,它实际上并没有插入正确(或全部)的值。我知道,因为我重新启动了应用程序,当我返回时,条目要么是随机错误(没有插入内容),要么是零。但有时是正确的 这里是我设置它的地方,是的,插入之前的值中的数据是正确的Ios 用于swift的sqlite不稳定,ios,sqlite,swift,Ios,Sqlite,Swift,我已经建立了使用sqlite的swift项目。有时,当插入时,它实际上并没有插入正确(或全部)的值。我知道,因为我重新启动了应用程序,当我返回时,条目要么是随机错误(没有插入内容),要么是零。但有时是正确的 这里是我设置它的地方,是的,插入之前的值中的数据是正确的 let update = "INSERT INTO ToDoItem (itemName, completed, goalDate) " + "VALUES (?, ?, ?);" var statement: COpaquePoin
let update = "INSERT INTO ToDoItem (itemName, completed, goalDate) " + "VALUES (?, ?, ?);"
var statement: COpaquePointer = nil
if sqlite3_prepare_v2(database, update, -1, &statement, nil) == SQLITE_OK {
let itemName = item.itemName as String
let completed = item.completed == true ? 1 : 0
sqlite3_bind_text(statement, 1, itemName, -1, nil)
sqlite3_bind_int(statement, 2, Int32(completed))
if let goalDate = item.goalDate?.toString() {
sqlite3_bind_text(statement, 3, goalDate, -1, nil)
} else {
sqlite3_bind_text(statement, 3, "", -1, nil)
}
//println("inserting \(itemName), \(completed) and \(item.goalDate?.toString())")
//println("")
}
if sqlite3_step(statement) != SQLITE_DONE {
println("error updateing table")
sqlite3_close(database)
return
}
sqlite3_finalize(statement)
sqlite3_close(database)
中间可以看到注释的打印,如果没有注释,那么ItNeNm有时会得到该字符串的一部分。
我也遇到了同样的问题。我找到了解决这个问题的方法
sqlite3_bind_text(statement, 1, itemName, -1, nil) --> itemName should be UTF8 String
您应该将itemName
转换为NSString
,并使用UTF8String
将字符串转换为UTF8
。正确的代码在这里是相同的
让itemName=item.itemName作为NSString
sqlite3_bind_text(语句,1,itemName.UTF8String,-1,nil)
祝你好运。这种行为实际上符合规范,错误就在你的代码中 问题的根源在于您要传递给
sqlite3\u bind\u text
的swift字符串中sqlite3\u bind\u text
接受作为const char*
的文本,该文本在Swift中桥接为UnsafePointer
。将Swift字符串
传递给接受UnsafePointer
的函数时的行为记录在。它说:
字符串将在缓冲区中自动转换为UTF8,并将指向该缓冲区的指针传递给函数
这可能就是你想要发生的
但它也说:
传递给函数的指针保证仅在函数调用期间有效。不要试图持久化指针并在函数返回后访问它
这就是你的bug的来源sqlite3\u bind\u text()
实际上可能会在调用sqlite3\u finalize()
之前将指针保留在准备好的语句中,以便它在以后的sqlite3\u step()
调用中使用它
另一个答案建议使用NSString.UTF8String
。这有一个较长的生命周期,似乎应该足够了。报告说:
这个C字符串是一个指向string对象内部结构的指针,它的生存期可能比string对象短,并且肯定不会有更长的生存期。因此,如果需要将C字符串存储在使用此属性的内存上下文之外,则应复制该字符串
这里的“记忆语境”似乎很模糊。我不确定这是否意味着当前函数,或者直到当前自动释放池耗尽,或者其他什么。如果是前两个中的一个,你就安全了。如果不是,我会说你仍然安全,因为它看起来像是NSString.UTF8String
已经在这种情况下使用了很长时间,没有任何问题。在swift中,SQLite没有定义SQLite\u TRANSIENT
和SQLite\u STATIC
,所以我们需要明确定义它
swift 3&4
定义SQLITE的以下属性
let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self)
let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
SQL函数
在绑定文本时添加SQLITE\u TRANSIENT
而不是nil
作为最后一个参数sqlite3\u bind\u text
let update = "INSERT INTO ToDoItem (itemName, completed, goalDate) " + "VALUES (?, ?, ?);"
var statement: OpaquePointer = nil
if sqlite3_prepare_v2(database, update, -1, &statement, nil) == SQLITE_OK {
let itemName = item.itemName as String
let completed = item.completed == true ? 1 : 0
sqlite3_bind_text(statement, 1, itemName, -1, SQLITE_TRANSIENT)
sqlite3_bind_int(statement, 2, Int32(completed))
if let goalDate = item.goalDate?.toString() {
sqlite3_bind_text(statement, 3, goalDate, -1, SQLITE_TRANSIENT)
} else {
sqlite3_bind_text(statement, 3, "", -1, SQLITE_TRANSIENT)
}
//println("inserting \(itemName), \(completed) and \(item.goalDate?.toString())")
//println("")
}
if sqlite3_step(statement) != SQLITE_DONE {
println("error updateing table")
sqlite3_close(database)
return
}
sqlite3_finalize(statement)
sqlite3_close(database)
引用自
您还必须使用SQLITE\u TRANSIENT
作为sqlite3\u bind\u text
的最后一个参数。SQLITE\u TRANSIENT不可用吗?请您提供建议。@SaurabhPrajapati我在Swift 3中找到了这个包含手动定义SQLITE_瞬态的答案:这应该是可以接受的答案