如何使用Swift删除SQLite中的项目

时间:2019-04-14 06:23:39

标签: swift sqlite

我正在尝试删除用户可以传递的主键。当我尝试删除项目时,什么也没有发生。基本上从表视图中,我将获得indexpath.row来找出用户向左滑动的项目,并使用该值删除该行。

func DeleteRowDatabase(inputId : Int32) -> Bool
{
        var db: OpaquePointer? = nil
        var returnCode : Bool = true


          if sqlite3_open(self.databasePath, &db) == SQLITE_OK {

        print("Successfully opened connection to database at \(self.databasePath)")

            // step 16d - setup query - entries is the table name you created in step 0
            var deleteStatement: OpaquePointer? = nil
            var deleteStatementString : String = "delete from entries where ID = ?"

            if sqlite3_prepare_v2(db, deleteStatementString, -1, &deleteStatement, nil) == SQLITE_OK {


            sqlite3_bind_int(deleteStatement, inputId, inputId)
             sqlite3_close(db);

            }

        }

        return returnCode

    }




func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {

        if editingStyle == .delete {
            //books.remove(at: indexPath.row)

            print("INDEX PATH")
            print(indexPath.row)

            var x: Int32 = Int32(indexPath.row)

            x = x + 1

            let mainDelegate = UIApplication.shared.delegate as! AppDelegate

            let returnCode : Bool = mainDelegate.DeleteRowDatabase(inputId: x)

        }
    }

2 个答案:

答案 0 :(得分:3)

您的主要问题是,您永远不会调用sqlite3_step来真正执行查询。

但是您还有其他问题。如果试图打开数据库(无论语句是否准备好),都需要调用sqlite3_close。完成后,还需要在准备好的语句上调用sqlite3_finalize。并且您为sqlite3_bind_int中的索引传递了错误的参数值。

func DeleteRowDatabase(inputId : Int32) -> Bool {
    var db: OpaquePointer? = nil
    var returnCode : Bool = false

    if sqlite3_open(self.databasePath, &db) == SQLITE_OK {
        print("Successfully opened connection to database at \(self.databasePath)")

        // step 16d - setup query - entries is the table name you created in step 0
        var deleteStatement: OpaquePointer? = nil
        var deleteStatementString : String = "delete from entries where ID = ?"

        if sqlite3_prepare_v2(db, deleteStatementString, -1, &deleteStatement, nil) == SQLITE_OK {
            sqlite3_bind_int(deleteStatement, 1, inputId)
            if sqlite3_step() == SQLITE3_DONE {
                returnCode = true
            }

            sqlite3_finalize(deleteStatement)
        }
    }

    sqlite3_close(db)

    return returnCode

}

答案 1 :(得分:2)

像rmaddy所说的

  1. 您需要调用sqlite3_step来实际执行准备好的语句。

无关,但我也建议:

  1. 调用sqlite3_close,无论例程是否成功。即使sqlite3_open没有成功,您也必须致电sqlite3_close。作为docs say

      

    无论打开时是否发生错误,与数据库连接句柄关联的资源都应在不再需要时通过将其传递给sqlite3_close()来释放。

  2. sqlite3_finalize准备好的语句。

  3. 我将使用guard语句来避免嵌套if语句的塔楼。

  4. 还要检查sqlite3_bind_xxx的返回码。

  5. 我会致电sqlite3_changes来确认是否删除了任何行。

  6. 我将以小写字母开头的方法名称。

因此:

func deleteRowDatabase(inputId: Int32) -> Bool {
    var db: OpaquePointer?

    defer { sqlite3_close(db) }
    guard sqlite3_open(databasePath, &db) == SQLITE_OK else {
        return false
    }

    print("Successfully opened connection to database at \(self.databasePath)")

    // step 16d - setup query - entries is the table name you created in step 0
    var statement: OpaquePointer?
    let sql = "DELETE FROM entries WHERE id = ?"

    guard sqlite3_prepare_v2(db, sql, -1, &statement, nil) == SQLITE_OK else {
        return false
    }

    defer { sqlite3_finalize(statement) }

    guard sqlite3_bind_int(statement, 1, inputId) == SQLITE_OK else {
        return false
    }

    guard sqlite3_step(statement) == SQLITE_DONE else {
        return false
    }

    guard sqlite3_changes(db) == 1 else {
        return false
    }

    return true
}

我还建议:

  1. 这种为每个SQL语句打开和关闭数据库的模式效率低下。我将打开数据库一次,然后将其保留。

  2. 我担心假设表中某行的ID对应于indexPath.row。如果您有10条记录并删除第一个记录,该怎么办。然后,您重新启动应用程序,现在有9条记录,但是现在表中的第一行对应于ID为2。我建议您在读表时构建一个ID值数组,并将这些值用于后续操作,而不是使用假设ID等于indexPath.row + 1