使用SQLite3和Swift选择输出错误

使用SQLite3和Swift选择输出错误,swift,database,sqlite,Swift,Database,Sqlite,我的任务是在Swift中制作一个移动应用程序来存储关于学生的数据。进入应用程序时,应创建数据库。应该有一个文本字段,用户可以从中将自己的名字插入数据库,还有一个按钮可以重新加载页面并查看数据库中的所有名字。此外,创建日期应存储在数据库中。 我有以下代码: import UIKit import SQLite3 class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { var

我的任务是在Swift中制作一个移动应用程序来存储关于学生的数据。进入应用程序时,应创建数据库。应该有一个文本字段,用户可以从中将自己的名字插入数据库,还有一个按钮可以重新加载页面并查看数据库中的所有名字。此外,创建日期应存储在数据库中。 我有以下代码:

import UIKit
import SQLite3

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    var db: OpaquePointer?
    var Students = [Student]()

    @IBOutlet weak var textFieldName: UITextField!
    @IBAction func buttonSave(_ sender: UIButton) {
        //getting values from textfields
        let name = textFieldName.text?.trimmingCharacters(in: .whitespacesAndNewlines)
        let d = Date()
        let formatter = DateFormatter()
        formatter.dateFormat = "dd.MM.yyyy"
        let date = formatter.string(from: d)

        //validating that values are not empty
        if(name?.isEmpty)!{
            textFieldName.layer.borderColor = UIColor.red.cgColor
            return
        }

        //creating a statement
        var stmt: OpaquePointer?

        //the insert query
        let queryString = "INSERT INTO Students (name, date) VALUES (?,?)"

        //preparing the query
        if sqlite3_prepare(db, queryString, -1, &stmt, nil) != SQLITE_OK{
            let errmsg = String(cString: sqlite3_errmsg(db)!)
            print("error preparing insert: \(errmsg)")
            return
        }

        //binding the parameters
        if sqlite3_bind_text(stmt, 1, name, -1, nil) != SQLITE_OK{
            let errmsg = String(cString: sqlite3_errmsg(db)!)
            print("failure binding name: \(errmsg)")
            return
        }

        if sqlite3_bind_text(stmt, 2, date, -1, nil) != SQLITE_OK{
            let errmsg = String(cString: sqlite3_errmsg(db)!)
            print("failure binding date: \(errmsg)")
            return
        }

        //executing the query to insert values
        if sqlite3_step(stmt) != SQLITE_DONE {
            let errmsg = String(cString: sqlite3_errmsg(db)!)
            print("failure inserting student: \(errmsg)")
            return
        }

        //emptying the textfields
        textFieldName.text=""
        readValues()

        //displaying a success message
        print("Student saved successfully")
    }

    @IBOutlet weak var tableViewStudents: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
            .appendingPathComponent("StudentsDatabase.sqlite")

        if sqlite3_open(fileURL.path, &db) != SQLITE_OK {
            print("error opening database")
        }

        if sqlite3_exec(db, "DROP TABLE Students", nil, nil, nil) != SQLITE_OK {
            let errmsg = String(cString: sqlite3_errmsg(db)!)
            print("error deleting table: \(errmsg)")
        }

        if sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS Students (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, date TEXT)", nil, nil, nil) != SQLITE_OK {
            let errmsg = String(cString: sqlite3_errmsg(db)!)
            print("error creating table: \(errmsg)")
        }

    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return Students.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "cell")
        let student: Student
        student = Students[indexPath.row]
        print(student.name)
        cell.textLabel?.text = student.name
        return cell
    }

    func readValues(){
        //first empty the list of heroes
        Students.removeAll()

        //this is our select query
        let queryString = "SELECT * FROM Students"

        //statement pointer
        var stmt:OpaquePointer?

        //preparing the query
        if sqlite3_prepare(db, queryString, -1, &stmt, nil) != SQLITE_OK{
            let errmsg = String(cString: sqlite3_errmsg(db)!)
            print("error preparing select: \(errmsg)")
            return
        }

        //traversing through all the records
        while(sqlite3_step(stmt) == SQLITE_ROW){
            let id = sqlite3_column_int(stmt, 0)
            let name = String(cString: sqlite3_column_text(stmt, 1))
            let date = String(cString: sqlite3_column_text(stmt, 2))

            //adding values to list
            Students.append(Student(id: Int(id), name: String(name), date: String(date)))
        }
        tableViewStudents.reloadData()
    }
}

class Student {
    var id: Int
    var name: String
    var date: String

    init(id: Int, name: String, date: String){
        self.id = id
        self.name = name
        self.date = date
    }
}
问题是,由于某种原因,学生的名字没有出现在表格中。取而代之的是,只显示日期的一部分,按学生姓名中的字母数分割。因此,如果我尝试在5月18日插入“John”,它将返回“18.0”-从日期中选取的4个符号。
感谢您提供有关如何解决此问题的任何帮助。

主要问题是您使用
字符串(cString:sqlite3\u column\u text(stmt,1)
读取存储的字符串,但您可以使用对
字符串
变量的简单引用来编写字符串,而不是使用
name.utf8CString
之类的内容。更新每个
sqlite3\u bind\u文本调用

代码中还有一些其他问题需要解决:

  • 切勿使用
    SELECT*FROM
    。无法保证字段将按特定顺序返回。请列出字段,以便传递给
    sqlite3\u column\u xxx
    的列索引匹配
  • 按钮save
    readValues
    中,您从未对准备好的语句调用
    sqlite3\u finalize
    。即使其他代码出现错误,您也需要重构代码以确保完成准备好的语句
  • 您的
    Student
    类可能应该是
    struct
    。然后您甚至不需要显式地提供
    init
  • 变量名称应以小写字母开头。将
    Students
    更改为
    Students
  • 按钮保存
    方法中,尽早检查
    名称
    的有效性。如果名称无效,则创建和格式化日期毫无意义

  • 非常感谢你的回答。