Becoming less afraid of unsafe mutable pointers in Swift (Xcode 6.0.1)


UnsafeMutablePointer: Before we begin

This post follows earlier posts on the same subject. Those posts were written when I first became acquainted with the UnsafeMutablePointer type. But the rules remain that you shouldn't become entangled with pointers unless you need to become entangled. At the same time don't be afraid of them, because blocking out their existence in your head isn't a wise thing to do either.

There follows some code snippets and an overview of how the UnsafeMutablePointer type might, might not, and in some cases almost definitely should not, be used.

Note: If you're unfamiliar with the concepts of memory allocation and memory addresses, then it might be wise to also seek out some information about this topic to make what is written easier to understand.

UnsafeMutablePointer: The basics

Let's recap the basics first of all. We'll allocate memory, initialise the memory with a value, access that stored value and then change the value. Finally, the stored object will be destroyed and the memory deallocated.
let aStr = UnsafeMutablePointer<String>.alloc(1)
// allocate a memory space

aStr.initialize("Hello Swift")
// initialise memory

aStr.memory // "Hello Swift"
// reveals what is in the memory location

aStr.memory = "Hello World"
// change the contents of the memory

aStr.destroy()
// destroy

aStr.dealloc(1)
// dealloc
The code I hope is clear enough from the comments.

UnsafeMutablePointer: What's your address?

Having gone over the basics, we're able to do some more advanced things. For example, we can access the memory address of the object we've stored and find its successor and predecessor in memory. We can also explore the distance between two stored objects.
let bStr = UnsafeMutablePointer<String>.alloc(1)
// allocate memory with a type

bStr.initialize("Hello World")
// initialize the memory location

bStr.debugDescription
// memory address returned as a hexadecimal (in string format)

bStr.hashValue
// memory address as an integer

bStr.successor().debugDescription
// following memory address

bStr.predecessor().debugDescription
// previous memory address, no guarantee of it being allocated or initialized. Attempt to access memory likely to cause a crash.

bStr.successor().hashValue
// following memory address

bStr.predecessor().hashValue
// previous memory address

bStr.distanceTo(aStr)
// distance between the two memory addresses, must be of same type. This example assumes that aStr hasn't yet been destroyed or deallocated

bStr.move() // move to a new memory address // "Equivalent to reading `memory` property and calling `destroy()` /// but more efficient."

bStr.dealloc(1)
// dealloc

UnsafeMutablePointer: Relative memory address 

In this example, it is decided exactly where the object will be placed in relation to another memory address.
var cStr = bStr.advancedBy(3)
// grab a pointer via advancedBy (we could also use successor and predecessor functions here

cStr.initialize("Hello World")
// initialize the memory location

cStr.memory = "Hi World"
// change the value

cStr.memory // "Hi World"

bStr.distanceTo(cStr) // 3, because we only advanced by 3 memory addresses
It's not something you need to do, or something that I'd recommend doing unless you are a highly-experienced memory management expert. I'm simply explaining what's there and what can be done, not what should be done.

UnsafeMutablePointer: Two pointers one address

Using the hashValue we can initialise an UnsafeMutablePointer to point at an identical memory location. This is demonstrated here:
let hashV = bStr.hashValue
// retrieve memory address

let dStr = UnsafeMutablePointer<String>(bitPattern: hashV)
// set up a second pointer

dStr.memory = "Hi ya"
// change the value

bStr.memory // "Hi ya"
// evidence that it is the same memory location

bStr.move() // "Equivalent to reading `memory` property and calling `destroy()` /// but more efficient." (Apple)

bStr.dealloc(1) // dealloc
// value of dStr will now be nil, because memory has been deallocated and the object destroyed

UnsafeMutablePointer: Copying from a memory address

There are a few other tricks up the UnsafeMutablePointer's sleeve. One of them is initializeFrom(), which enables us to copy the raw memory of a pointer (and any number of successive pointers) like so:
var dStr = UnsafeMutablePointer<String>.alloc(1)
// set up a second pointer
dStr.initialize("Hello")
// dStr.put("Good")

var eStr = UnsafeMutablePointer<String>.alloc(1)
eStr.initializeFrom(dStr, count: 1)
eStr.memory // Hello
eStr.memory = "Goodbye"

dStr.move() // "Hello"
eStr.move() // "Goodbye"

dStr.dealloc(1)
eStr.dealloc(1)
Another is to adopt the SinkType protocol and to have a put() method that releases the object after use.

Endorse on Coderwall

Comments

  1. This comment has been removed by the author.

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Anthony .. at last, someone creating Code examples that coder can use .. rather than verbose text with no context!

    On the last 'box' : var dStr = UnsafeMutablePointer.alloc(1)
    Is this missing a 'String' before the alloc? (had to remove angle brackets as Blogger threw a wobbly!)

    Thanks,
    AJ

    ReplyDelete
    Replies
    1. Thanks for your kind words. You are absolutely correct. I forgot to encode the angle brackets and it was treated as a tag in the HTML, hence the <String> part was invisible.

      Delete

Post a Comment