Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Splitting Data into chunks in Swift 3

I need to send images read from the Photo Library over the wire - in chunks of 5MB.

I read an image from the library using: PHImageManager.requestImageData(for:options:resultHandler:) and get a Data object. I would then like to efficiently split the data into chunks (without copying the memory). What would be the best way to do that?

This is what I have so far:

    imageData.withUnsafeBytes { (unsafePointer: UnsafePointer<UInt8>) -> Void in

        let totalSize = data.endIndex
        var offset = 0

        while offset < totalSize {
            let chunkSize = offset + uploadChunkSize > totalSize ? totalSize - offset : uploadChunkSize
            let chunk = Data(bytesNoCopy: unsafePointer, count: chunkSize, deallocator: Data.Deallocator.none)

            // send the chunk...

           offset += chunkSize
        }
    }

However I get this error at compile time:

Cannot convert value of type 'UnsafePointer' to expected argument type 'UnsafeMutableRawPointer'

If I use mutableBytes:

data.withUnsafeMutableBytes { (unsafePointer: UnsafeMutablePointer<UInt8>) -> Void in... }

Then I get the compile-time error:

Cannot use mutating member on immutable value: 'data' is a 'let' constant

Which is correct, since I do not really want to make changes to the image data. I only want to send one chunk of it at a time.

Is there a better way to do this?

like image 491
GK100 Avatar asked Mar 03 '17 16:03

GK100


1 Answers

Hi there!

I need the same behaviour and came up with this solution. You pointed the error right and the solution is just to create the UnsafeMutableRawPointer with the UnsafePointer address. It's the fastest solution I found yet.

One other thing is to add the offset to the base address of the mutRawPointer when you create a chunk.

50MB data in 2MB chunks takes ~ 0.009578s

func createChunks(forData: Data) {

    imageData.withUnsafeBytes { (u8Ptr: UnsafePointer<UInt8>) in
        let mutRawPointer = UnsafeMutableRawPointer(mutating: u8Ptr)
        let uploadChunkSize = 2097152
        let totalSize = imageData.count
        var offset = 0

        while offset < totalSize {

            let chunkSize = offset + uploadChunkSize > totalSize ? totalSize - offset : uploadChunkSize
            let chunk = Data(bytesNoCopy: mutRawPointer+offset, count: chunkSize, deallocator: Data.Deallocator.none)
            offset += chunkSize
        }
    }
}
like image 198
Johannes Knust Avatar answered Nov 05 '22 01:11

Johannes Knust