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?

1

3 Answers 3

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])
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, I did overthink it; For future reference to others, UnsafeMutablePointer<Int32> DOES allow for subscripting.
As a side note, I'm curious why guard let buffer = buffer.memory as? [Int32] else { fatalError() } would fail. Any thoughts on that?
memory points to the first element of your array, not the array itself hence not castable
How about guard let buffer = buffer as? [Int32] else { ... }?
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
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!

3 Comments

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<Int32>?
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
You can probably obtain the length from whatever source gave you the pointer.
1

Maybe you instead use UnsafeBufferPointer?

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.