Я делаю преобразование Swift 5 в код, который я не совсем понимаю, устаревший код от предыдущего разработчика. Я получил:
'withUnsafeBytes' is deprecated: use withUnsafeBytes(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R` instead
для:
func toArray<T>(type: T.Type) -> [T] {
return self.withUnsafeBytes {
[T](UnsafeBufferPointer(start: $0, count: self.count/MemoryLayout<T>.stride))
}
}
Я хочу заменить его на это, но я не уверен, что он делает то же самое:
func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
var array = [T](repeating: 0, count: self.count/MemoryLayout<T>.stride)
_ = array.withUnsafeMutableBytes { copyBytes(to: $0) }
return array
}
Используется в контексте этих двух эффектов:
static func extractPacketSizeFromIV(iv: Data) -> Int32? {
let array = iv.toArray(type: Int32.self)
guard array.count == 4 else { return nil }
let r0 = array[0].bigEndian
let r1 = array[1].bigEndian
let r2 = array[2].bigEndian
return r2 ^ r1 ^ r0
}
static func extractGuidFromIV(iv: Data) -> Int32? {
let array = iv.toArray(type: Int32.self)
guard array.count == 4 else { return nil }
let r0 = array[0].bigEndian
let r1 = array[1].bigEndian
let r2 = array[2].bigEndian
let r3 = array[3].bigEndian
return r3 ^ r2 ^ r1 ^ r0
}
Ваш код похож на версии Swift 4 и Swift 5 из туда и обратно Типы номеров Swift в/из данных — вы могли бы оставить комментарий и попросить разъяснений :)
Во-первых, ваш toArray
определяется как расширение Data
, верно?
(Пожалуйста, разъясняйте такие вещи, когда вы пишете вопросы.)
Ваш код будет работать так же, как код от предыдущего разработчика в вашем случае использования, но я бы написал эквивалент в Swift 5 следующим образом:
func toArray<T>(type: T.Type) -> [T] {
return self.withUnsafeBytes {
[T]($0.bindMemory(to: type))
}
}
bindMemory(to: type)
создает UnsafeBufferPointer<T>
(как в исходном коде) из параметра, переданного из нового withUnsafeBytes
— это UnsafeRawBufferPointer
.
Потенциальная проблема с bindMemory заключается в том, что он требует, чтобы память была правильно выровнены для связанного типа, и, как правило, трудно сказать, как выровнена память данного значения данных. Вот почему я предложил copyMemory в stackoverflow.com/a/38024025/1187415.
Да, конечно, но этот вопрос дал понять, что Data
состоит только из этих трех/четырех значений Int32
, поэтому я бы не стал излишне усложнять это с помощью copyMemory
или того, что у вас есть (особенно если буфер был большим, однородная коллекция ). Конечно, если бы у вас был более сложный Data
с гетерогенными типами данных разного размера, вы бы подняли его на следующий уровень, но не здесь, ИМХО.
Я бы использовал предложенную замену, а именно withUnsafeBytes(_:)
, первым параметром которой является UnsafeRawBufferPointer
, напрямую, не создавая массив и не копируя буферы без необходимости, например:
static func extractPacketSizeFromIV(iv: Data) -> Int32? {
return iv.withUnsafeBytes { rawBuffer -> Int32 in
let buffer = rawBuffer.bindMemory(to: Int32.self)
let r0 = buffer[0].bigEndian
let r1 = buffer[1].bigEndian
let r2 = buffer[2].bigEndian
return r2 ^ r1 ^ r0
}
}
Очевидно, что если ваш Data
был более сложным, чем этот (например, гетерогенная полезная нагрузка с большим количеством разных типов разного размера), могут потребоваться другие подходы, но если это простой буфер с простым набором Int32
, вышеприведенное эффективный способ получения необходимых значений.
... если базовая память выровнена для значений Int32.
Спасибо @Rob, я добавил больше информации о том, как они используются.