Unsafe pointers in Swift: A first look (Part I, Xcode 6 Beta 6; updated Swift 3, Xcode 8)


Let's suppose I want to alter an existing colour in some way, and that I decide to do this by taking the original hue, saturation and brightness values of the colour before increasing (or decreasing them).
var col = UIColor(hue: 0.4, saturation: 0.3, brightness: 0.7, alpha: 1.0)
Having established a colour, I discover that there is a getHue() method for instances of a UIColor, which is perfect for the task of capturing colour values. But as soon as I start writing the get hue method in Swift, I'm hit with all these unsafe pointer things:
col.getHue(hue: UnsafeMutablePointer<CGFloat>, saturation: UnsafeMutablePointer<CGFloat>, brightness: UnsafeMutablePointer<CGFloat>, alpha: UnsafeMutablePointer<CGFloat>)
While I might understand that a CGFloat is a type of float and that the pointer must be pointing at that float, it doesn't mean I know how to provide the information the parameters are demanding. And I am also a bit scared by the repeated use of the word 'unsafe'. Should I be using this method at all?

Real-world use

In real world use, I need to know two things: how to define the instance of a Type and when to put an ampersand (&) in front of an instance name. And once I understand that an unsafe mutable thingy whatsit can be replaced with an inout variable (identified with the & symbol) then I'm away.
var a:CGFloat = 0.0
var b:CGFloat = 0.0
var c:CGFloat = 0.0
var d:CGFloat = 0.0
col.getHue(&a, saturation: &b, brightness: &c, alpha: &d)

a // 0.4 (get the value of the CGFloat object) 
b // 0.3
c // 0.7
d // 1.0
Despite all the wordy scaremongering, it turns out that's all there is to it. I can now increase or decrease any one of those CGFloat values and create a new colour from them.

For the curious

But the curious will still ask what one of them unsafe thingywhatsits is. Well this is for them (you?):
var col = UIColor(hue: 0.4, saturation: 0.3, brightness: 0.7, alpha: 1.0)

var a = UnsafeMutablePointer<CGFloat>.alloc(1) // allocate memory for one object
a.initialize(0) // initialize with a value of 0
var b = UnsafeMutablePointer<CGFloat>.alloc(1)
b.initialize(0)
var c = UnsafeMutablePointer<CGFloat>.alloc(1)
c.initialize(0)
var d = UnsafeMutablePointer<CGFloat>.alloc(1)
d.initialize(0)

col.getHue(a, saturation: b, brightness: c, alpha: d)

a.memory // 0.4 (the value of the CGFloat object) 
b.memory // 0.3
c.memory // 0.7
d.memory // 1.0

a.destroy() // first destroy object to return to deinitialized state
a.dealloc(1) // deallocate the memory so that the object can go out of memory
b.destroy()
b.dealloc(1)
c.destroy()
c.dealloc(1)
d.destroy()
d.dealloc(1)

Swift 3, Xcode 8

var col = UIColor(hue: 0.4, saturation: 0.3, brightness: 0.7, alpha: 1.0)

var a = UnsafeMutablePointer<CGFloat>allocate(capacity: 1) // allocate memory for one object
a.initialize(to: 0) // initialize with a value of 0
var b = UnsafeMutablePointer<CGFloat>.allocate(capacity: 1)
b.initialize(to: 0)
var c = UnsafeMutablePointer<CGFloat>.allocate(capacity: 1)
c.initialize(to: 0)
var d = UnsafeMutablePointer<CGFloat>.allocate(capacity: 1)
d.initialize(to: 0)

col.getHue(a, saturation: b, brightness: c, alpha: d)

// use move() to retrieve value and deinitialize at the same time
a.move() // 0.4 (the value of the CGFloat object)
b.move() // 0.3
c.move() // 0.7
d.move() // 1.0


a.deallocate(capacity: 1) // deallocate the memory so that the object can go out of memory
b.deallocate(capacity: 1)
c.deallocate(capacity: 1)
d.deallocate(capacity: 1)
iOS veterans (v.4 and before) will be familiar with releasing objects from memory, and the alloc/init terminology will also be fresh in the minds of newer Objective-C developers. But the method of getting at those values might not be familiar to any of these developers nor people starting from scratch with Swift.

Will this ever be useful to know?

Apple's own documentation does little more than explain how to write a nil pointer, while encouraging us towards the ampersand (&) inout syntax. And for most developers this will be all you need to know to make your  app work.  At the same time, having this chunk of Swift where you don't know what is happening can be disorientating. So while you might never use the second block of code in your work (or conversely there might be some C scenario where it is required) it is to my mind enabling to at least know what can be done.

Thanks to this StackOverflow post for putting me on the right track and to @UINT_MIN for completing the circle.

Comments

  1. Thanks for this post ... UnsafeMutablePointers were giving me a pain in the butt. I didn't realize I had to initialize them to a value before using them.

    ReplyDelete
  2. Nice post, and thanks for the Swift 3 update

    ReplyDelete

Post a Comment