Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting Objective-C malloc to Swift

I am working on a project that was written in Objective-C and needs to be updated to Swift. We use a C file for transferring data.

Here is the code I was given in Objective-C:

- (NSData *)prepareEndPacket {
    UInt8 *buff_data;
    buff_data = (uint8_t *)malloc(sizeof(uint8_t)*(PACKET_SIZE+5));
    // Call to C File
    PrepareEndPacket(buff_data);
    NSData *data_first = [NSData dataWithBytes:buff_data length:sizeof(uint8_t)*(PACKET_SIZE+5)];
    return data_first;
}

In the C .h file I have this for reference:

#define PACKET_SIZE     ((uint32_t)128)

I can not seem to find a good way of converting this to Swift. Any help would be appreciated.

like image 441
temp_ Avatar asked Nov 09 '18 20:11

temp_


1 Answers

malloc and free actually work fine in Swift; however, the UnsafeMutablePointer API is more "native". I'd probably use Data's bytesNoCopy for better performance. If you want, you can use Data(bytes:count:), but that will make a copy of the data (and then you need to make sure to deallocate the pointer after making the copy, or you'll leak memory, which is actually a problem in the Objective-C code above since it fails to free the buffer).

So, something like:

func prepareEndPacket() -> Data {
    let count = PACKET_SIZE + 5
    let buf = UnsafeMutablePointer<UInt8>.allocate(capacity: count)

    PrepareEndPacket(buf)

    return Data(bytesNoCopy: buf, count: count, deallocator: .custom { ptr, _ in
        ptr.deallocate()
    })
}

By using bytesNoCopy, the Data object returned is basically a wrapper around the original pointer, which will be freed by the deallocator when the Data object is destroyed.

Alternatively, you can create the Data object from scratch and get a pointer to its contents to pass to PrepareEndPacket():

func prepareEndPacket() -> Data {
    var data = Data(count: PACKET_SIZE + 5)

    data.withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) in
        PrepareEndPacket(ptr)
    }

    return data
}

This is slightly less efficient, since the Data(count:) initializer will initialize all the Data's bytes to zero (similar to using calloc instead of malloc), but in many cases, that may not make enough of a difference to matter.

like image 145
Charles Srstka Avatar answered Oct 18 '22 09:10

Charles Srstka