2016-08-10 89 views
2

我目前正在編寫一個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條款,我需要最終確定他們的陳述。

據我所知,這是類似於deinit類的swift,但有deinit s的功能呢?

例如(代碼,我想它是這樣,但不工作):

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

回答

6

是的,有一個「DEINIT的功能」 - 這就是所謂的defer

一個defer聲明就轉移出現的defer聲明範圍之外程序控制之前用於執行代碼英寸

注意,不像你的假設的例子中,defer語句必須之前出現無論發生什麼情況都會導致它執行的清理,而不是在封閉範圍的末尾。在一般情況下,它的工作原理是這樣的:

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

這裏,cleanup(resource)得到不論功能是否退出,因爲if something調用,還是因爲它達到其範圍的結束(doOtherStuff()後)。

你不能把一個deferif裏面就像你問 - 它只是推遲到它在範圍內的出口,所以它會在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 
} 
0

怎麼樣使用defer關鍵字。

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