Swift 5.0: "withUnsafeBytes" устарело: используйте "withUnsafeBytes <R> (...)
Ранее я использовал этот код в Swift 4.2 для генерации идентификатора:
public static func generateId() throws -> UInt32 {
let data: Data = try random(bytes: 4)
let value: UInt32 = data.withUnsafeBytes { $0.pointee } // deprecated warning!
return value // + some other stuff
}
withUnsafeBytes
устарела в Swift 5.0. Как я могу решить это?
Ответы
Ответ 1
В Swift 5 метод withUnsafeBytes()
в Data
вызывает замыкание с (нетипизированным) UnsafeRawBufferPointer
, и вы можете load()
значение из необработанной памяти:
let value = data.withUnsafeBytes { $0.load(as: UInt32.self) }
(сравните Как правильно использовать Data.withUnsafeBytes? на форуме Swift). Обратите внимание, что для этого необходимо, чтобы память была выровнена по 4-байтовой границе. Для альтернатив см. типы номеров Swift туда и обратно в/из данных.
Также обратите внимание, что в Swift 4.2 вы можете создать случайное 32-разрядное целое число, просто используя новый Random
API:
let randomId = UInt32.random(in: .min ... .max)
Ответ 2
В Xcode 10.2 Swift 5 с помощью $0.load(as:)
не работал для меня, как при чтении из указателя, так и при записи в него.
Вместо этого использование $0.baseAddress?.assumingMemoryBound(to:)
, кажется, работает хорошо.
Пример чтения из буфера указателя (код не связан с вопросом):
var reachability: SCNetworkReachability?
data.withUnsafeBytes { ptr in
guard let bytes = ptr.baseAddress?.assumingMemoryBound(to: Int8.self) else {
return
}
reachability = SCNetworkReachabilityCreateWithName(nil, bytes)
}
Пример записи в указатель буфера (код не связан с вопросом):
try outputData.withUnsafeMutableBytes { (outputBytes: UnsafeMutableRawBufferPointer) in
let status = CCKeyDerivationPBKDF(CCPBKDFAlgorithm(kCCPBKDF2),
passphrase,
passphrase.utf8.count,
salt,
salt.utf8.count,
CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1),
rounds,
outputBytes.baseAddress?.assumingMemoryBound(to: UInt8.self),
kCCKeySizeAES256)
guard status == kCCSuccess else {
throw Error.keyDerivationError
}
}
Код вопроса будет выглядеть следующим образом:
let value = data.withUnsafeBytes {
$0.baseAddress?.assumingMemoryBound(to: UInt32.self)
}
В тех случаях, когда предупреждение 'withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(…)
сохраняется, создается впечатление, что компилятор может запутаться, когда замыкание имеет только одну строку. Создание замыкания из двух или более строк может устранить неоднозначность.
Ответ 3
Я получил эту ошибку, когда пытался выяснить учебник по потоку сжатия. Чтобы заставить его работать, я добавил шаг преобразования необработанного указателя буфера в UnsafePointer
Оригинальный код из учебника, над которым я работал.
-> где ввод: данные
-> где поток: сжатие_потока
//Method that shows the deprecation alert
return input.withUnsafeBytes { (srcPointer: UnsafePointer<UInt8>) in
//holder
var output = Data()
//Source and destination buffers
stream.src_ptr = srcPointer //UnsafePointer<UInt8>
stream.src_size = input.count
… etc.
}
Код с преобразованием, чтобы вышеуказанный код работал с допустимым методом
return input.withUnsafeBytes { bufferPtr in
//holder
var output = Data()
//Get the Raw pointer at the initial position of the UnsafeRawBuffer
let base: UnsafeRawPointer? = bufferPtr.baseAddress
//Unwrap (Can be combined with above, but kept it separate for clarity)
guard let srcPointer = base else {
return output
}
//Bind the memory to the type
let count = bufferPtr.count
let typedPointer: UnsafePointer<UInt8> = srcPointer.bindMemory(to: UInt8.self, capacity: count)
// Jump back into the original method
stream.src_ptr = typedPointer //UnsafePointer<UInt8>
}
Ответ 4
Еще один способ исправить это предупреждение - использовать bindMemory (to :).
var rawKey = Data(count: rawKeyLength)
let status = rawKey.withUnsafeMutableBytes { rawBytes -> Int32 in
guard let rawBytes = rawBytes.bindMemory(to: UInt8.self).baseAddress else {
return Int32(kCCMemoryFailure)
}
return CCSymmetricKeyUnwrap(alg, ivBytes, iv.count, keyBytes, key.count, wrappedKeyBytes, wrappedKey.count, rawBytes, &rawKeyLength)
}