我已经设置了swift项目来使用sqlite。有时,插入时实际上并不插入正确的(或全部)值。我知道,因为我重新启动应用程序,当我回来时,条目是随机错误(没有插入的东西)或零。但有时是正确的。
这里是我设置的地方,是的,插入前的数据中的数据是正确的。
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)
你可以在中间看到注释掉的println,如果没有注释掉,那么itemName有时会得到该字符串的一部分。
答案 0 :(得分:22)
我遇到了同样的问题。我找到了解决这个问题的方法。
sqlite3_bind_text(statement, 1, itemName, -1, nil) --> itemName should be UTF8 String
您应将itemName
转换为NSString
并使用UTF8String
将字符串转换为UTF8
。正确的代码在这里是相同的
let itemName = item.itemName as NSString
sqlite3_bind_text(statement, 1, itemName.UTF8String, -1, nil)
祝你好运。
答案 1 :(得分:4)
在快速的SQLite中,没有定义SQLITE_TRANSIENT
和SQLITE_STATIC
,因此我们需要显式定义它。
交换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_TRANSIENT
时,添加nil
而不是sqlite3_bind_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)
答案 2 :(得分:-2)
此行为实际上符合规范,并且代码中存在错误。
问题的根源在于您传递给String
的快速sqlite3_bind_text
。 sqlite3_bind_text
接受该文字为const char*
,在Swift中将其作为UnsafePointer<CChar>
桥接。将Swift String
传递给接受UnsafePointer<CChar>
的函数时的行为记录在&#34;常量指针&#34; Interacting with C APIs的一部分。它说:
该字符串将在缓冲区中自动转换为UTF8,并将指向该缓冲区的指针传递给该函数。
这可能是你想要发生的事情。
但是它还说:
传递给函数的指针保证仅在函数调用期间有效。在函数返回后,不要试图保持指针并访问它。
这是你的bug的来源。实际上,sqlite3_bind_text()
确实会将指针保留在预准备语句中,直到sqlite3_finalize()
被调用,以便它可以在将来的sqlite3_step()
调用中使用它。
另一个答案建议使用NSString.UTF8String
。这有一个更长的寿命,似乎应该足够了。 documentation说:
此C字符串是指向字符串对象内部结构的指针,该结构的生命周期可能短于字符串对象,并且肯定不会有更长的生命周期。因此,如果需要将C字符串存储在使用此属性的内存上下文之外,则应复制该字符串。
&#34;记忆环境&#34;这里看起来很模糊。我不确定它是否意味着当前的功能,或者直到当前的自动释放池被耗尽,或其他什么。如果它是前两个之一,那么你是安全的。如果没有,我会说你仍然是安全的,因为似乎NSString.UTF8String
已经在这样的情况下使用了很长时间没有问题..