Ошибки при обновлении кода во избежание предупреждений об устаревании с помощью UnsafeMutableBytes в swift 5 - PullRequest
5 голосов
/ 27 марта 2019

Я обновился до swift 5, и одна из зависимостей, которые я использую, не будет компилироваться в swift 5. Я исправил это, но теперь я получаю 350+ предупреждений об устаревании по всему файлу.Все они похожи на это:

withUnsafeMutableBytes устарело: используйте withUnsafeMutableBytes<R>(_: (UnsafeMutableRawBufferPointer) throws -> R) rethrows -> R вместо

И это фрагмент кода (в основном это просто вызовфункции библиотеки ac):

var k = Data(count: crypto_generichash_keybytes())
k.withUnsafeMutableBytes { kPtr in
    flutter_sodium.crypto_generichash_keygen(kPtr)
}

Для справки, в приведенном выше коде crypto_generichash_keybytes () просто возвращает size_t, а сигнатура crypto_generichash_keygen равна void crypto_generichash_keygen(unsigned char k[crypto_generichash_KEYBYTES]);.

Я выяснил (как в этом ответе говорится), что для решения этой проблемы следует вызвать kPtr.baseAddress:

var k = Data(count: crypto_generichash_keybytes())
k.withUnsafeMutableBytes { kPtr in
    flutter_sodium.crypto_generichash_keygen(kPtr.baseAddress)
}

, поскольку для этого следует использовать вариант withUnsafeMutableBytes<ResultType>, а не устаревший withUnsafeMutableBytes<ResultType, ContentType>,Однако вместо этого это приводит к ошибке

значение типа 'UnsafeMutablePointer <_>' не имеет члена 'baseAddress'.

Если я явно укажу resultType и kPtr:

var k = Data(count: crypto_generichash_keybytes())
k.withUnsafeMutableBytes { (kPtr: UnsafeMutableRawBufferPointer) -> Void in
    flutter_sodium.crypto_generichash_keygen(kPtr.baseAddress)
}

Вместо этого я получаю

UnsafeMutableRawBufferPointer 'не конвертируется в' UnsafeMutablePointer <_> '.

Есть ли быстрые экспертытам, что может помочь мне найти правильный способ сделать это?Я знаю, что предупреждения - это просто предупреждения, но я предпочитаю иметь код, который компилируется без предупреждений.

Я взглянул на Swift 5.0: «withUnsafeBytes» устарело: используйте «withUnsafeBytes (...) перед публикацией этого вопроса, и это не помогает моей ситуации, так как я не загружаю указатель, а использую данные.Кроме того, я сделал именно то, что говорит мне документация, но это все равно не помогает.

РЕДАКТИРОВАТЬ: Чтобы быть немного более ясным, некоторые из 350+ предупреждений были связаны с кодом, где Data выделяется в коде, однако некоторые из них, где я получаю Data от внешнегоисточник.Это выглядит примерно так:

let args = call.arguments as! NSDictionary
let server_pk = (args["server_pk"] as! FlutterStandardTypedData).data
let server_sk = (args["server_sk"] as! FlutterStandardTypedData).data
let client_pk = (args["client_pk"] as! FlutterStandardTypedData).data

var rx = Data(count: flutter_sodium.crypto_kx_sessionkeybytes())
var tx = Data(count: flutter_sodium.crypto_kx_sessionkeybytes())
let ret = rx.withUnsafeMutableBytes { rxPtr in
  tx.withUnsafeMutableBytes { txPtr in
    server_pk.withUnsafeBytes { server_pkPtr in
      server_sk.withUnsafeBytes { server_skPtr in
        client_pk.withUnsafeBytes { client_pkPtr in
          flutter_sodium.crypto_kx_server_session_keys(rxPtr, txPtr, server_pkPtr, server_skPtr, client_pkPtr)
        }
      }
    }
  }
}

с соответствующим вызовом метода

SODIUM_EXPORT
int crypto_kx_client_session_keys(unsigned char rx[crypto_kx_SESSIONKEYBYTES],
                                  unsigned char tx[crypto_kx_SESSIONKEYBYTES],
                                  const unsigned char client_pk[crypto_kx_PUBLICKEYBYTES],
                                  const unsigned char client_sk[crypto_kx_SECRETKEYBYTES],
                                  const unsigned char server_pk[crypto_kx_PUBLICKEYBYTES])
            __attribute__ ((warn_unused_result));

(и я знаю, что код на самом деле не является оптимальным быстрым, но когда речь идет о взаимодействии между дротиком иswift - вот что пришла команда флаттера для того, как это сделать).

Когда я задал вопрос, я пытался отогнать его до самого простого случая, но в этом случае был конкретный ответ, который отличается отобщая проблема у меня.

1 Ответ

6 голосов
/ 27 марта 2019

Я бы не использовал Data здесь - Data представляет нетипизированную коллекцию «сырых» байтов, однако crypto_generichash_keygen хочет изменяемый указатель на напечатанную память.Причина, по которой UnsafeMutablePointer<T> вариант withUnsafeMutableBytes устарел, заключается в том, что это принципиально неправильная абстракция для предоставления нетипизированной памяти.

Самый простой способ получить буфер типизированной памяти в Swift - использовать Array:

var k = [UInt8](repeating: 0, count: crypto_generichash_keybytes())
flutter_sodium.crypto_generichash_keygen(&k)

Впоследствии вы всегда можете превратить полученный буфер в значение Data, сказав Data(k).

Другой вариант - использовать UnsafeMutableBufferPointer:

let k = UnsafeMutableBufferPointer<UInt8>.allocate(capacity: crypto_generichash_keybytes())
defer {
  k.deallocate()
}
flutter_sodium.crypto_generichash_keygen(k.baseAddress!)
// Now use the buffer `k` – just make sure you finish using it before the end of
// the scope when `deallocate()` gets called!

В отличие от Array, это избавляет от необходимости предварительно заполнять результирующий буфер нулями перед передачей их в C API, однако это, вероятно, не имеет значения.Но точно так же, как Array, вы можете превратить такой буфер в Data, просто сказав Data(k).


Для случаев, когда вы получаете значение Data из какого-либо внешнего источника инеобходимо передать его в API в виде типизированного указателя, самый простой и безопасный вариант - просто превратить его в массив перед передачей, сказав Array(someData).

Например:

let args = call.arguments as! NSDictionary
let server_pk = (args["server_pk"] as! FlutterStandardTypedData).data
let server_sk = (args["server_sk"] as! FlutterStandardTypedData).data
let client_pk = (args["client_pk"] as! FlutterStandardTypedData).data

var rx = [UInt8](repeating: 0, count: flutter_sodium.crypto_kx_sessionkeybytes())
var tx = [UInt8](repeating: 0, count: flutter_sodium.crypto_kx_sessionkeybytes())

flutter_sodium.crypto_kx_server_session_keys(
  &rx, &tx, Array(server_pk), Array(server_sk), Array(client_pk)
)

Вы , вероятно, могли бы использовать withUnsafeBytes и вызывать bindMemory для базового указателя, но я бы не одобрил это, так как это меняет тип базовой памяти, что может незначительно влиять на надежность любого другогоБыстрый код разделяет эту память из-за того, что вы переключаете тип из-под него.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...