2016-08-10 5 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()).

Вы не можете поставить 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 
} 
0

Что собирается использовать defer ключевое слово.

func updateColumn(params...) -> Bool { 
    // code... 
    defer { 
     sqlite3_finalize(statementPointer) 
    } 
} 
Смежные вопросы