Swift 5.0: «withUnsafeBytes» устарела: используйте «withUnsafeBytes <R>(...) - PullRequest
20 голосов
/ 27 марта 2019

Ранее я использовал этот код в 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.Как я могу решить это?

Ответы [ 2 ]

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

В 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)
8 голосов
/ 03 апреля 2019

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

...