2

I've got a legacy codebase with this function:

-(void)foo: (int *)buffer {
  myArray[0] = buffer[0];
  myArray[1] = buffer[1];
  myArray[2] = buffer[2];
  myArray[3] = buffer[3];
}

In Swift, this method is written as the following:

func foo(buffer: UnsafeMutablePointer<Int32>) {
}

The int pointer is now considered an UnsafeMutablePointer<UInt32>. I'm having trouble accessing the subscripts of buffer in Swift; i.e. I cannot call buffer[0] like this:

func foo(buffer: UnsafeMutablePointer<Int32>) {
  myArray[0] = buffer[0] // won't compile, buffer treated as Int32
}

Out of desperation, even knowing that UnsafeMutablePointer<Int32> is ultimately resolved as a Int32 type in Swift, I've tried the following:

guard let buffer = buffer.memory as? [Int] else { fatalError() }

guard let buffer = buffer as? [Int] else { fatalError() }

guard let buffer = buffer.memory as? [Int32] else { fatalError() }

guard let buffer = buffer as? [Int32] else { fatalError() }

Could someone point me to the right direction on understanding how I could access the subscript members like how the Objective-C code did?

Kelvin Lau
  • 6,373
  • 6
  • 34
  • 57
  • 1
    Related: [Converting an UnsafePointer with length to a Swift Array type](http://stackoverflow.com/questions/32606989/converting-an-unsafepointer-with-length-to-a-swift-array-type). – Martin R Jun 23 '16 at 18:21

3 Answers3

3

UnsafePointer is meant to model a single location in memory. For dealing with a buffer, use UnsafeBufferPointer.

UnsafeBufferPointer can be subscripted like an Array, and has bound checking (since it requires you give it a count).

You don't even have to do that manual conversion like in your Objective C code, you can initialize Array directly from UnsafeBufferPointer, very easily:

func foo(buffer: UnsafeMutablePointer<Int32>) {
    myArray = Array(UnsafeBufferPointer(start: pointer, count: 4))
}

This solution is even generic: UnsafeBufferPointer can infer its type from the UnsafePointer you give it, and pass that info along to Array, to make it automagically create a [Int32]

Note: Remember to deallocate your UnsafePointer!

Alexander
  • 59,041
  • 12
  • 98
  • 151
  • Thanks. Really cool approach. I confirmed that this also works. May I ask if you know of a method to safely find the `count` of the `UnsafeMutablePointer`? – Kelvin Lau Jun 23 '16 at 18:12
  • 1
    Nope, this is too "low level" for that. The `UnsafeMutablePointer` just knows an address and a type. It has no way of knowing the length, which is why you have to supply it. If you're dealing with a C string, you can iterate to find the first `NUL` character. Other than that, there's no way to know – Alexander Jun 23 '16 at 18:14
  • You can probably obtain the length from whatever source gave you the pointer. – Alexander Jun 23 '16 at 18:15
3

You are overthinking it:

class MyClass {
    var myArray = [Int32](count: 4, repeatedValue: 0)

    func foo(buffer: UnsafeMutablePointer<Int32>) {
        for i in 0..<4 {
            myArray[i] = buffer[i]
        }
    }
}

You can change myArray to [Int32] to make it match buffer. Or you can cast buffer to Int:

myArray[i] = Int(buffer[i])
Code Different
  • 90,614
  • 16
  • 144
  • 163
  • Thanks, I did overthink it; For future reference to others, `UnsafeMutablePointer` DOES allow for subscripting. – Kelvin Lau Jun 23 '16 at 17:57
  • As a side note, I'm curious why `guard let buffer = buffer.memory as? [Int32] else { fatalError() }` would fail. Any thoughts on that? – Kelvin Lau Jun 23 '16 at 17:59
  • 1
    `memory` points to the first element of your array, not the array itself hence not castable – Code Different Jun 23 '16 at 18:02
  • How about `guard let buffer = buffer as? [Int32] else { ... }`? – Kelvin Lau Jun 23 '16 at 18:03
  • Didn't realize `UnsafeMutablePointer` was subscriptable, that's good to know. Not a fan of this approach in general, as there's a cleaner, built-in way to do this – Alexander Jun 23 '16 at 18:06
1

Maybe you instead use UnsafeBufferPointer?

http://swiftdoc.org/v2.2/type/UnsafeBufferPointer/

tommybananas
  • 5,718
  • 1
  • 28
  • 48