0

I have Swift code which reads a binary file representing a sequence of UInt32 values like this:

let fileData = binaryFile.readData(ofLength: 44)

guard fileData.count > 0 else { break }

let headerData = fileData.withUnsafeBytes {
    Array(UnsafeBufferPointer<UInt32>(start: $0, count: 11))
}

let polyCount = headerData[1].bigEndian
let polyFlags = headerData[2].bigEndian

I'd not used the program containing this code for a while, but when returning to it recently, it still works as expected, but now gives a deprecation warning:

"withUnsafeBytes is deprecated: use withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R instead"

I've searched for quite a long time for an un-deprecated way to do this without success. There are many examples across the web (including in stackoverflow) but almost all of them written before this deprecation into effect. Frankly, I've fried my brain hunting and trying suggestions! I am prepared to accept that I'm missing something totally obvious ("If it's getting complicated, you're doing it wrong."), but I work in an environment where I have no colleagues to ask .. except here.

Any guidance would be much appreciated.

RamsayCons
  • 61
  • 3

3 Answers3

1

RamsayCons's own solution is nice, but what about the performance? I think, it could be better if we reduce all unnecessary operation.

extension Data {
    func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
        Array(unsafeUninitializedCapacity: self.count/MemoryLayout<T>.stride) { (buffer, i) in
            i = copyBytes(to: buffer) / MemoryLayout<T>.stride
        }
    }
}

measured performance gain depends, but number of execution per second is at least doubled. Bigger the data, bigger advantage!

user3441734
  • 13,374
  • 2
  • 25
  • 44
1
self.dataArray = data.withUnsafeBytes{ Array($0.bindMemory(to: UInt32.self))}
RJG
  • 21
  • 2
0

Well, letting some time pass restored brain function! I found an answer (in stackoverflow, of course):

round trip Swift number types to/from Data

some way into that question/answer is:

extension Data {
    func toArray<T>(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
        var array = Array<T>(repeating: 0, count: self.count/MemoryLayout<T>.stride)
        _ = array.withUnsafeMutableBytes { copyBytes(to: $0) }
        return array
    }
}

The trick is that Arrays are not necessarily stored in contiguous memory so simply copying enough bytes in order to the destination doesn't do it. I hope this helps the next person hunting with a fried brain!!

RamsayCons
  • 61
  • 3