3

I am trying to reference to an array inside a function.
Something like this: a and b are arrays of Ints.

  var inout refArr = &a
  if(!someFlag) {
     refArr = &b
  }
  refArr[someIndex] = 30

This does not compile, can I only use inout for function arguments? If so, how do I do a reference/pointer inside a function?

3
  • What does the rest of your function look like? Commented Mar 1, 2015 at 16:56
  • I am changing the values in the array and I need them to be persistence Commented Mar 1, 2015 at 17:08
  • The best way is to just use inout parameters in the function Commented Mar 1, 2015 at 17:11

3 Answers 3

3

& can only be used to pass a variable as an inout argument to a function. So the easiest solution is perhaps to use a helper function inside your function:

func foo() {

    func helper(inout array : [Int]) {
        array[2] = 99
    }

    var a = [1, 2, 3, 5, 6]
    var b = [4, 5, 6, 7]
    let someFlag = true

    if someFlag {
        helper(&a)
    } else {
        helper(&b)
    }

    // ...
}

You can create a reference to the array using UnsafeMutableBufferPointer:

let ref = someFlag ?
    UnsafeMutableBufferPointer(start: &a, count: a.count) :
    UnsafeMutableBufferPointer(start: &b, count: b.count)
ref[2] = 99

But there are two problems with this solution:

  • UnsafeMutableBufferPointer() creates a non-owning reference, so the compiler might decide to deallocate the array while the reference is still used.
  • There is no bounds check on the array.

So to make this work safely, you have to add some code:

withExtendedLifetime(a) { () -> Void in
    withExtendedLifetime(b) { () -> Void in
        let ref = someFlag ?
            UnsafeMutableBufferPointer(start: &a, count: a.count) :
            UnsafeMutableBufferPointer(start: &b, count: b.count)
        if ref.count > 2 {
            ref[2] = 99
        }
    }
}

which is a bit ugly.

Sign up to request clarification or add additional context in comments.

Comments

0

You can use inout parameters in your function to accomplish this. Use the inout modifier for your parameters and use the ampersand (&) when passing a value into the function like so:

func swapTwoInts(inout a: Int, inout b: Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var x = 5
var y = 10

swapTwoInts(&x, &y)

x // 10
y // 5

Comments

0

Arrays in swift are not guaranteed to be contiguous in memory the way they are in C, so to insure you have access to a contiguous block, you have to either pass them to a function with an inout parameter or--if you really want a reference to an array within the function--create an UnsafeMutableBufferPointer like this[1]:

var someFlag: Bool = false
var a = ["a", "b", "c"]
var b = ["d", "e", "f"]

var refArr = a.withUnsafeMutableBufferPointer { (inout output: UnsafeMutableBufferPointer<String>) -> UnsafeMutableBufferPointer<String> in

    return output
}

println(refArr[1]) //Will Output 'a'

if !someFlag {
    refArr = b.withUnsafeMutableBufferPointer { (inout output: UnsafeMutableBufferPointer<String>) -> UnsafeMutableBufferPointer<String> in

        return output
    }
}

println(refArr[1]) //Will Output 'e'

1. Thread Safety with Swift Arrays

2 Comments

withUnsafeMutableBufferPointer creates (as far as I know, not 100% sure), a "non-owning" reference. So the compiler is free to deallocate the arrays a, b while the reference still exists.
In the vast majority of cases it seems like best practice would incline towards the use of inout parameters and not to mess around with C-style references if you don't have to, but do you have any insight into how to persist UnsafeMutableBufferPointer references, if as you say, they create an unowned reference

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.