var a = [1,2,3]
let ptr1 = UnsafeMutablePointer<Int>(&a[0]) //works fine
let index = 0
let ptr2 = UnsafeMutablePointer<Int>(&a[index]) //compiler throws error
error: cannot invoke initializer for type
UnsafeMutablePointer<Int>
with an argument list of type(inout Int)
Why the latter one doesn't compile? Is there anything I am missing here?
I wanted to do like a below snippet.
class Holder {
var numbers: [Int] = [1,2,3,4]
var modifier: Modifier
init(index: Int) {
self.modifier = Modifier(UnsafeMutablePointer(&self.numbers) + index)
}
}
class Modifer {
var ptr: UnsafeMutablePointer<Int>
init(_ ptr: UnsafeMutablePointer<Int>) {
self.ptr = ptr
}
func change(to: Int) {
self.ptr.pointee = to
// expected the change to be reflected in numbers array
// but as Rob Napier said it became invalid and throws EXC_BAD_ACCESS
}
}
How can I achieve the above expected result?
Note that neither of these is a valid way to create an UnsafeMutablePointer. Swift is free to deallocate a immediately after the last time it is referenced, so by the time you use these pointers, they may be invalid. The tool you want is a.withUnsafeMutableBufferPointer
.
That said, the correct syntax here is:
let ptr2 = UnsafeMutablePointer(&a) + index
Looking at your updated code, there's no way for this to make sense on Array. I think you're assuming that Arrays are reference types. They're value types. There's no way to change a piece of numbers
. Any change to it replaces the entire array with a completely different array. Swift has some clever copy-on-write tricks to make this efficient, and in practice it may not actually replace the entire array, but you should program as though it did. You should consider the following line:
array[1] = 2
to be equivalent to:
array = <a new array that is identical, but element 1 has been replaced by 2>
This means that pointers into Array
are meaningless outside of very controlled situations (such as inside a withUnsafeMutableBufferPointer
block).
What you want is something more like this:
class Holder {
var numbers: [Int] = [1,2,3,4]
private(set) var modifier: ((Int) -> ())! // ! is an artifact of capturing self in init
init(index: Int) {
self.modifier = { [weak self] in self?.numbers[index] = $0 }
}
}
let holder = Holder(index: 2)
holder.numbers // [1, 2, 3, 4]
holder.modifier(0)
holder.numbers // [1, 2, 0, 4]