Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Function Pointers in My Swift CCurl Library

DZone's Guide to

Function Pointers in My Swift CCurl Library

Here's a great tutorial for using function pointers in Swift CCurl library, which allows you to receive and process data internally.

· Mobile Zone
Free Resource

Download this comprehensive Mobile Testing Reference Guide to help prioritize which mobile devices and OSs to test against, brought to you in partnership with Sauce Labs.

By default, libcurl writes the data it receives to stdout. This is less than useful when writing an application, as we want to store the received data internally and process it.

This is done using the libcurl settings CURLOPT_WRITEFUNCTION which takes a function pointer where you can process the received data and CURLOPT_WRITEDATA which lets you set a pointer to something that can store the received data. You get access to this pointer within your write function.

To do this with my CCurl wrapper around libcurl, I needed to create two new curl_easy_setopt shim functions called curl_easy_setopt_func and curl_easy_setopt_pointer in sots_curl.c. These functions aren't hard to write as they are simply setting the correct type on the third parameter so that Swift knows how to handle them.

On the Swift side of things, we use a class to hold the bytes we receive so that we can easily pass it to lib curl and not have to worry about managing the memory of data we're adding:

public class Received {
    var data = String()
}

We then tell curl about it:

let received = Received()
let pReceived = UnsafeMutablePointer(Unmanaged.passUnretained(received).toOpaque())

curl_easy_setopt_pointer(handle, CURLOPT_WRITEDATA, pReceived)

We create an instance of Received and then create an UnsafeMutablePointer to it and set that as our curlWRITEDATA property.

I ended up using a class as I couldn't work out how to pass a String directly without segmentation faults when executing the app! I think this is because I would need to manage the memory of the String myself, but if I use a class, then I'm only passing the pointer to the class around and it can manage the memory of the String property within it.

The callback now looks like this:

let writeFunc: curl_func = { (buffer, size, num, p) -> Int in
    let received = Unmanaged<Received>.fromOpaque(COpaquePointer(p)).takeUnretainedValue()
    let bytes = UnsafeMutablePointer<UInt8>(buffer)
    let count = size*num
    for idx in 0..<count {
        received.data.append(UnicodeScalar(bytes[idx]))
    }
    return count
}
curl_easy_setopt_func(handle, CURLOPT_WRITEFUNCTION, writeFunc)

We convert p back into a Received object and then can append to the data string property. Usefully UnicodeScalarconverts an integer into the relevant character, though we probably need some error handling here.

Now, I'm at point where I can wrap all this into a Swift class and talk to web services.

Analysts agree that a mix of emulators/simulators and real devices are necessary to optimize your mobile app testing - learn more in this white paper, brought to you in partnership with Sauce Labs.

Topics:
swift ,curl

Published at DZone with permission of Rob Allen, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}