8

In Swift, assigning an array to a new variable actually makes of copy. For example (as in Apple doc for Array):

var numbers = [1, 2, 3, 4, 5]
var numbersCopy = numbers
numbers[0] = 100
print(numbers)
// Prints "[100, 2, 3, 4, 5]"
print(numbersCopy)
// Prints "[1, 2, 3, 4, 5]"

How do I actually get a pointer to the same array, so modifying the elements is reflected in the same array? (The reason for this is I access in static instances of another class, e.g. "SomethingManager.sharedInstance.arrayList[aKey]" and I'll like to shorten it to an assigned pointer variable.)

(I'm interested to know how to do this in Swift 4 and 5. I don't see any existing question for Swift language.)

EDIT:

I'm providing my rationale for the need to have a pointer instead of a copy.

Say, I have the following code:

var childrenTasks = [Int64: [TaskRef]]()

defined in a class, which is accessed:

MyClass.singleton.parentTask[parentTaskID].childrenTask[taskRefID]

As you can see that the code to access childrenTask is very long. I'd like to have a pointer, just an illustration :-

var aPointerToChildrenTasks = MyClass.singleton.parentTask[parentTaskID].childrenTask[taskRefID] // I want a pointer, not a copy!
aPointerToChildrenTask.remove(at: anIndex) // if it is a pointer, I can manipulate the same set of values of the array

It will help make my code easier to read. I need a pointer to manipulate the same set of values so I use a "var". If it is only read-only, I can use a "let", but still it has performance penalty if I get a copy.

How do I get a pointer in Swift? Is this possible? (I know that in Kotlin it is possible as it is pass-by reference.)

EDIT: I see some suggestion that this question is a duplicate. No, it is not. Those other questions/answers are specifically focused on inout parameters. For my case, I just want a pointer to work in the same function/method.

Cœur
  • 37,241
  • 25
  • 195
  • 267
ikevin8me
  • 4,253
  • 5
  • 44
  • 84
  • Please find the link. [Array - pass by reference](https://stackoverflow.com/questions/24250938/swift-pass-array-by-reference) – prex Feb 01 '19 at 07:56
  • That link is talking about passing into a function using inout. I mean, I just need a new var to work with. – ikevin8me Feb 01 '19 at 07:59
  • Without function: [how to pass array by reference without function](https://stackoverflow.com/questions/35391394/how-to-pass-array-by-reference-without-function-swift) – prex Feb 01 '19 at 08:07
  • 4
    Can you provide more details on your actual problem? `SomethingManager` is a *class* (reference type), so `SomethingManager.sharedInstance` is (essentially) a pointer, and all accesses to `SomethingManager.sharedInstance.arrayList` would access the same array anyway. – Martin R Feb 01 '19 at 08:17
  • @MartinR, `I'll like to shorten it to an assigned pointer variable` — it looks like ability to access it via some shortened(?) name is needed, without need to type `SomethingManager.sharedInstance.arrayList` all the time. – user28434'mstep Feb 01 '19 at 12:13
  • Possible duplicate of [How to return an inout (reference) in a swift function?](https://stackoverflow.com/questions/27539533/how-to-return-an-inout-reference-in-a-swift-function) – Cristik Feb 02 '19 at 08:07

3 Answers3

12

Not a ‘pure’ Swift solution, but using NSArray will give you the reference semantics you desire.

NSArray is toll-free bridgeable to Array, so you can use plain as instead of as!

var numbers = [1, 2, 3, 4, 5]
var numbersCopy = numbers as NSArray
numbers[0] = 100
print(numbers)

[100, 2, 3, 4, 5]

print(numbersCopy as Array)

[1, 2, 3, 4, 5]

If you are modifying the 'copy' you will need to use a NSMutableArray.

Edit: oops I think I was confused by the naming of your variable numbersCopy. I see now that you want the 'copy' to share the same value as the original. By capturing the variable numbers in a block, and executing that block later, you can get the current value of numbers, and you don't need to use NSArray at all.

var numbers = [1, 2, 3, 4, 5]
var numbersCopy = {numbers}
numbers[0] = 100
print(numbers)

[100, 2, 3, 4, 5]

print(numbersCopy())

[100, 2, 3, 4, 5]

Aaron Kreipe
  • 309
  • 3
  • 8
1

If it's just about convenience, consider making a utility function like this:

func withChildrenTasks(of parentTaskID: Int64, taskRefID: TaskRef, body: (inout [TaskRef]) -> ()) {
    body(&MyClass.singleton.parentTask[parentTaskID].childrenTasks[taskRefID])
}

withChildrenTasks(of: parentTaskID, taskRefID: taskRefID) { tasks in
    // do stuff with tasks
}

You can't create an "inout var", but you can always make a callback that accepts an inout parameter, so this is an easy workaround. I expect that the Swift compiler would be pretty good about optimizing it away.

If it's because you actually want to share the array reference, you will either need to wrap it in a reference type (class SharedArray<T> { var array = [T]() } might be enough for that purpose), or you could use NSMutableArray from Foundation.

zneak
  • 134,922
  • 42
  • 253
  • 328
0

Use a computed property:

var numbers = [1, 2, 3, 4, 5]
var numbersCopy: [Int] {
    get { numbers }
    set { numbers = newValue }
}

numbers[0] = 100
print(numbers)
// Prints "[100, 2, 3, 4, 5]"
print(numbersCopy)
// Prints "[100, 2, 3, 4, 5]"

numbersCopy[1] = 200
print(numbers)
// Prints "[100, 200, 3, 4, 5]"
print(numbersCopy)
// Prints "[100, 200, 3, 4, 5]"
user3225395
  • 581
  • 6
  • 23