#250: Improvements to C APIs in Swift 3 

Datetime:2016-08-23 04:15:22          Topic: Swift           Share

We’ve covered a little about working with C APIs in Swift back inBite #189. Swift 3 brings us a ton of new goodies and improvements around C APIs , let's dive right in and take a look.

Swift 3improves upon a number of areas of C API usage in Swift , but the biggest one is importing functions as members. Essentially, taking free floating C functions , renaming them, and shoving them onto a type as functions .

One place where this behavior really shines is when using CoreGraphics to draw into a view .

Here's some basic drawing code in Swift 2 :

guard let context: CGContext = UIGraphicsGetCurrentContext() else { return }

CGContextSetStrokeColorWithColor(context, UIColor.redColor().CGColor)
CGContextSetLineWidth(context, 2)
CGContextDrawPath(context, .Stroke)

In Swift 3 , the code to do the same would be:

guard let context: CGContext = UIGraphicsGetCurrentContext() else { return }

context.strokeColor = UIColor.red().cgColor
context.lineWidth = 2
context.drawPath(mode: .Stroke)

The mechanisms powering this conversion under the hood are pretty neat. The full (now implemented) proposal can be found here , but here's a quick overview:

The first is a bit of automatic inference. Many APIs (like CoreGraphics and CoreFoundation ) use consistent ( albeit often verbose ) naming schemes for their functions . The Swift compiler can now exploit this to (for example) detect functions returning a specific type and convert them into init functions in Swift.

So this C function would come in to Swift 2 like this:

func CGColorCreate(space: CGColorSpace?, _ components: UnsafePointer<CGFloat>) -> CGColor?

But in Swift 3 it's an init function :

extension CGColor {
  init?(space: CGColorSpace?, components: UnsafePointer<CGFloat>)
}

There's tons more of these automatic inferences for things like detecting getter/setter pairs of functions , converting Boolean functions into Bool properties , etc.

Finally, authors of C libraries can customize exactly how their functions are imported into Swift using the new swift_name macro.

Here's an example from the proposal that demonstrates how we can define which type our function gets imported on to.

struct Point3D rotatePoint3D(Point3D point, float radians)
__attribute__((swift_name("Point3D.rotate(self:radians:)")));

The string parameter we pass to swift_name has a bunch of little extra syntax to import things as inits , regular functions , getters/setters , etc.

As always when talking about Swift improvements, it's a good idea to check out the full proposal for more info.





About List