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.
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) // deallocThe 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 addressesIt'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>Another is to adopt the SinkType protocol and to have a put() method that releases the object after use..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)
This comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteAnthony .. at last, someone creating Code examples that coder can use .. rather than verbose text with no context!
ReplyDeleteOn 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
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