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. Как я могу это решить?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
55
0
24 782
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

В 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)

Можете ли вы сказать мне, как обстоят дела с этим: data.withUnsafeBytes {CC_SHA256($0, CC_LONG(data.count), &buffer)} ??

Michal Zaborowski 27.03.2019 17:00

@mientus: взгляните на обновление Swift 5 в stackoverflow.com/a/25762128/1187415.

Martin R 27.03.2019 17:12

@MartinR, когда есть ноль / нереально, тогда я получил Thread 1: EXC_BAD_ACCESS (code=1, address=0x20) как мы можем с этим справиться?

Jack 30.03.2021 13:00

В 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>(…) сохраняется, оно похоже на компилятор может запутаться, если в замыкании всего одна строка. Создание замыкания с двумя или более строками может устранить двусмысленность.

Я использовал другой способ реализации второго примера. Это позволяет избежать использования withUnsafeMutableBytes: var derivedKeyData = [UInt8](repeating: 0, count: keyByteCount);let derivationStatus = CCKeyDerivationPBKDF(CCPseudoRandomAlgorithm(kCCPBKDF2),pass‌​phrase,passphrase.ut‌​f8.count,Array(salt)‌​,salt.count,hash,rou‌​nds,&derivedKeyData,‌​derivedKeyData.count‌​).

Baran Emre 04.04.2019 10:04

Правда, в некоторых случаях указатель (косвенность) на выделенный целочисленный массив работает гораздо проще. Преобразование назад и вперед из данных в массив UInt8 также довольно просто.

Eneko Alonso 04.04.2019 16:10

Я получаю сообщение об ошибке: значение типа «UnsafePointer<_>» не имеет члена «baseAddress»

iosbegindevel 18.10.2019 09:11

Я получил эту ошибку, когда пытался понять учебник по сжатию потока. Чтобы заставить его работать, я добавил шаг преобразования необработанного указателя буфера в 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>
}

Еще один способ исправить это предупреждение — использовать привязать память (к:).

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)
}

Другие вопросы по теме