Swift convert Data to UnsafeMutablePointer

2019-07-23 16:17发布

问题:

I'm calling a function in an objective c class from swift.

-(char *)decrypt:(char *)crypt el:(int)el{}

when calling this function from swift, it asks for an UnsafeMutablePointer<Int8> as the value for the parameter 'crypt'

the value for the 'crypt' is comming from a server and it is a base64encoded string. So I decode that string and got a Data object.

let resultData = Data(base64Encoded: base64String)

Now I need to pass this data to the above mentioned function. I have tried to convert this Data object to a UnsafeMutablePointer<Int8>

resultData?.withUnsafeBytes { (u8Ptr: UnsafeMutablePointer<Int8>) in
                    let decBytes = tea?.decrypt(u8Ptr , el: el)}

But it is not compiling. Gives below error

'UnsafeMutablePointer' is not convertible to 'UnsafePointer<_>'

I don't know much about objective c. So could anyone help me to pass this parameter to objective c function.

回答1:

you have to change UnsafeMutablePointer to UnsafePointer

UnsafePointer

resultData?.withUnsafeBytes {(bytes: UnsafePointer<CChar>)->Void in
            //Use `bytes` inside this closure

        }

UnsafeMutablePointer

 var data2 = Data(capacity: 1024)
data2.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer<UInt8>) -> Void in
                 //Use `bytes` inside this closure

            })


回答2:

Edit, updated my answer for two things:

  • Not returning the pointer from withUnsafeBytes
  • Accounting for Swift 5' deprecation warning: 'withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R instead
// buffer pointer captured is converted to byte pointer which is used in the block to decode the base64 encoded Data
encodedStringData.withUnsafeMutableBytes { (rawBufferPtr: UnsafeMutableRawBufferPointer) in
    if let rawPtr = rawBufferPtr.baseAddress {
        let decodedString = String(bytesNoCopy: rawPtr, length: rawBufferPtr.count, encoding: .utf8, freeWhenDone: false)
        print(decodedString!)
    }
}

Note: Swift 5 doesn't allow you to access encodedStringData from within the withUnsafeMutableBytes block! Read Swift 5 Exclusivity Enforcement for why.

Capturing the pointer outside of the block is apparently not recommended, it works but the behavior can get to be undefined in the future

Old answer:

This will help someone looking for getting to the underlying raw bytes (in a UnsafeMutablePointer<UInt8> representation) of a Data object as a variable for further use (instead of having to write all of the logic in the withUnsafeMutableBytes block).

var encodedStringData = Data(base64Encoded: "Vmlub2QgaXMgZ3JlYXQh")!

// byte pointer variable used later to decode the base64 encoded Data
let rawPtr: UnsafeMutablePointer<UInt8> = encodedStringData.withUnsafeMutableBytes { (bytePtr: UnsafeMutablePointer<UInt8>) in bytePtr }

let decodedString = String(bytesNoCopy: rawPtr, length: encodedStringData.count, encoding: .utf8, freeWhenDone: false)

print(decodedString, encodedStringData)