离开功能前执行代码

时间:2016-08-10 04:46:55

标签: swift sqlite

我目前正在研究sqlite数据库的一些代码。我注意到在准备查询之后,我总是需要在退出函数之前完成查询(sqlite3_finalize(statementPointer))。除了填补所有可能性之外,有没有办法做到这一点?

例如:

func updateColumn(db: COpaquePointer, name: String, x: sqlite3_int64, y: String!=nil) -> Bool {
    var statement = "UPDATE MY_TABLE SET X=?"
    var statementPointer: COpaquePointer = nil
    if y != nil {
        statement += ", Y=?"
    }
    statement += " WHERE NAME=?"
    if sqlite3_prepare_v2(db, statement, -1, &statementPointer, nil) != SQLITE_OK {
        return false
    } else if sqlite3_bind_int64(statementPointer, 1, x) != SQLITE_OK {
        // Note this code here
        sqlite3_finalize(statementPointer)
        return false
    }

    if y != nil {
        if sqlite3_bind_text(statementPointer, 2, y, -1, nil) != SQLITE_OK {
            // Note this repetition
            sqlite3_finalize(statementPointer)
            return false
        }
    }

    if sqlite3_step(statementPointer) != SQLITE_DONE {
        // Note this repetition
        sqlite3_finalize(statementPointer)
        return false
    }
    // Note this repetition
    sqlite3_finalize(statementPointer)
    return true
}

当然,这只是我提出来解释这一点。在实际代码中,还有许多其他if条款,我需要完成它们的陈述。

我知道这对于swift中的类来说就像deinit,但是函数也有deinit吗?

例如(我希望它的代码类似但不起作用的代码):

func updateColumn(params...) -> Bool {
    // code...
    deinit {
        sqlite3_finalize(statementPointer)
    }
}

2 个答案:

答案 0 :(得分:9)

是的,有一个“deinit for functions” - 它被称为defer

  

defer语句用于在将defer语句出现的范围之外的程序控制转移之前执行代码。

请注意,与您的假设示例不同,defer语句必须在之前出现,否则可能会导致执行清理,而不是在封闭范围的末尾。一般来说,它的工作原理如下:

func doStuff() {
    let resource = acquireResource()
    defer {
        cleanup(resource)
    }
    if something { return }
    doOtherStuff()
}

此处,无论函数是由cleanup(resource)退出还是因为它到达其范围的末尾(if something之后),都​​会调用doOtherStuff()

你不能像你要求的那样将defer置于if内 - 它只会延迟它所在范围的退出,所以它会在结束时执行if身体。但是defer确实与guard很好地构成...在你的情况下,你可能想要这样的东西:

func updateColumn(db: COpaquePointer, name: String, x: sqlite3_int64, y: String!=nil) -> Bool {
    var statementPointer: COpaquePointer = nil
    //... Other stuff...

    guard sqlite3_prepare_v2(db, statement, -1, &statementPointer, nil) == SQLITE_OK
        else { return false }
    // after this you want any possible exit to do finalize, so put the defer here
    defer { sqlite3_finalize(statementPointer) }

    // every `return` after here, true or false, will execute the `defer` clause
    guard sqlite3_bind_int64(statementPointer, 1, x) == SQLITE_OK 
        else { return false }

    guard y != nil && sqlite3_bind_text(statementPointer, 2, y, -1, nil) == SQLITE_OK 
        else { return false }

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

    return true
}

答案 1 :(得分:1)

如何使用defer关键字。

func updateColumn(params...) -> Bool {
    // code...
    defer {
        sqlite3_finalize(statementPointer)
    }
}