Swift: Как узнать, нужно ли копировать экземпляр? - PullRequest
1 голос
/ 03 марта 2020

В каждом из приведенных ниже примеров необходимо ли копировать blob.0 или text? Откуда вы знаете?

Настройка

import SQLite3
private let static_destructor = unsafeBitCast(0, to: sqlite3_destructor_type.self)
private let transient_destructor = unsafeBitCast(-1, to: sqlite3_destructor_type.self)

Примеры

  1. bind_blob

    func bind_blob(_ stmt: OpaquePointer, _ blob: (UnsafeRawPointer, Int32)) {
      sqlite3_bind_blob(stmt, 1, blob.0, blob.1, transient_destructor)
    }
    
  2. bind_blobs

    func bind_blobs(_ stmt: OpaquePointer, _ blobs: [(UnsafeRawPointer, Int32)]) {
      for (index, blob) in blobs.enumerated() {
        sqlite3_bind_blob(stmt, Int32(index+1), blob.0, blob.1, transient_destructor)
      }
    }
    
  3. bind_text

    func bind_text(_ stmt: OpaquePointer, _ text: String) {
      sqlite3_bind_text(stmt, 1, text, -1, transient_destructor)
    }
    
  4. bind_texts

    func bind_texts(_ stmt: OpaquePointer, _ texts: [String]) {
      for (index, text) in texts.enumerated() {
        sqlite3_bind_text(stmt, Int32(index+1), text, -1, transient_destructor)
      }
    }
    

Ie, я должен использовать static_destructor вместо transient_destructor в любом из примеров?

Смежный вопрос: Когда использовать SQLITE_TRANSIENT против SQLITE_STATI C?

1 Ответ

1 голос
/ 07 марта 2020

В ваших функциях bind_text и bind_texts вам необходимо использовать временный деструктор. Когда вы передаете Swift String функции C в качестве аргумента const char *, Swift не гарантирует, что указатель останется действительным после возврата функции C. В статье Вызов функций с параметрами указателя говорится следующее:

Указатель, передаваемый функции, гарантированно действителен только на время вызова функции. Не сохраняйте указатель и не обращайтесь к нему после того, как функция вернулась.

В ваших bind_blob и bind_blobs функциях зависит, откуда взялся UnsafeRawPointer и когда вы выполните SQL заявление. Если вы получаете указатель с использованием какой-либо функции Swift withUnsafeWhatever, то указатель недействителен после возврата функции withUnsafeWhatever. Например, документация withUnsafeBytes(of:_:) гласит следующее:

Аргумент указателя буфера действителен только на время выполнения замыкания.

Если вы связываете свой BLOB-объект, выполняете инструкцию, а затем больше не используете привязку, тогда вы можете использовать деструктор stati c. Это нормально с деструктором stati c:

let data: Data = ...
data.withUnsafeBytes { rawBuffer in
    if let pointer = rawBuffer.baseAddress {
        bind_blob(statement, (pointer, rawBuffer.count))
        execute(statement)
        // No more use of statement unless the parameter is rebound.
    }
}

Но это не нормально с деструктором stati c:

let data: Data = ...
data.withUnsafeBytes { rawBuffer in
    if let pointer = rawBuffer.baseAddress {
        bind_blob(statement, (pointer, rawBuffer.count))
    }
}
execute(statement)
...