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

Launching an app doesn’t need to be daunting. Whether you’re just getting started or need a refresher on mobile app testing best practices, this guide is your resource! Brought to you in partnership with Perfecto

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.

Keep up with the latest DevTest Jargon with the latest Mobile DevTest Dictionary. Brought to you in partnership with Perfecto.

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.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

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

{{ parent.tldr }}

{{ parent.urlSource.name }}