SQLite插入后查询Name与Director字段值异常一致问题求助
问题原因分析
你的问题根源在于SQLite的sqlite3_column_text返回的指针是临时缓冲区的引用,再搭配CHAR(255)字段的特性,最终导致字符串读取时出现了覆盖问题。
具体拆解一下:
- 你用
CHAR(255)定义字段,SQLite会自动用空格把字符串填充到255个字符长度,而这些填充的空格并不是C字符串的终止符\0; sqlite3_column_text返回的指针指向SQLite内部的临时缓冲区,每次调用sqlite3_column_*系列函数(包括多次调用sqlite3_column_text)时,这个缓冲区的内容会被覆盖;- 你的查询代码里,先调用
sqlite3_column_text(selectStatement, 1)获取Name的指针,但没有立即转成Swift String保存;之后调用sqlite3_column_text(selectStatement, 3)获取Director的指针,此时临时缓冲区已经被Director的内容覆盖。后续用这两个指针创建String时,两个指针都指向了最后一次调用的内容(也就是Director的值); - 再加上
CHAR(255)的空格填充,读取Name字段时因为没有\0终止符,String会一直读取内存直到遇到终止符,刚好后续的Director字段内容就在内存中,所以最终Name的内容被Director覆盖,且长度和原Name一致。
解决方法
针对这个问题,有两个关键修复点:
1. 立即转换临时指针为Swift String
每次调用sqlite3_column_text后,立刻把它转换成Swift String并保存,避免临时缓冲区被后续调用覆盖。
修改selectAllMovie方法里的循环部分:
while sqlite3_step(selectStatement) == SQLITE_ROW { // 立即转换每个列的内容并保存,避免指针被覆盖 let id = sqlite3_column_int(selectStatement, 0) // 处理Name字段 let nameCString = sqlite3_column_text(selectStatement, 1) let name = nameCString != nil ? String(cString: nameCString!) : "" let year = sqlite3_column_int(selectStatement, 2) // 处理Director字段 let directorCString = sqlite3_column_text(selectStatement, 3) let director = directorCString != nil ? String(cString: directorCString!) : "" let movie = Movie( ID: id, name: name, year: year, director: director ) print("Name --> \(name)") print("Director --> \(director)") print("Name value out is: \(movie.name), Director Value out is: \(movie.director)") result.append(movie) }
2. 改用TEXT类型替代CHAR(255)(推荐)
CHAR(n)类型强制填充空格的特性不仅浪费存储空间,还容易引发C字符串读取问题。SQLite中更推荐用TEXT类型存储字符串,它会自动适配字符串长度,不需要填充空格,从根源上避免这类内存读取问题。
修改createMovieTable方法的表结构:
let createTableQuery = """ CREATE TABLE Movie ( ID INTEGER PRIMARY KEY NOT NULL, Name TEXT, Year INTEGER, Director TEXT ); """
验证修复效果
修改完成后重新运行插入和查询代码,就能看到Name和Director字段的值可以正确区分,不会再出现互相覆盖的情况了。
内容的提问来源于stack exchange,提问作者user3547778
相关产品推荐
相关产品推荐

