1

I have an array of struct 'Pair' (Data) and I want to change the element in the array if some condition is met. I have followed the documentation https://docs.swift.org/swift-book/LanguageGuide/Methods.html and created a 'setValue' method with mutating

But when I debug the code, I see the value of the pair variable get changed. But the array 'data?.pairs' does not get changed to the new value 'Point(1,2). Can you please tell what am I missing?

public struct Data {
 var pairs: [Pair<Point>]
}
var array = data?.pairs ?? []
for index in 0..<array.count {
    var pair = data?.pairs[index]
                  
    if /* some test */ {
       print ("Found match")
       pair?.setValue(Point(1,2))   // `pair` is updated, but data?.paris[index] is not updated.
    }
}

struct Pair<Value: Comparable>{
    var key: Value
    var value: Value

    init(_ key: Value, _ value: Value) {
        self.key = key
        self.value = value
    }

    mutating func setValue(_ value: Value) {
        self.value = value
    }
}
2
  • 1
    Not related to your question but you should choose another name to your structure. Data is a native Swift type (Foundation). Commented Sep 9, 2020 at 6:42
  • This might help stackoverflow.com/a/63485959/6791677 Commented Sep 9, 2020 at 6:49

2 Answers 2

2

Pair is a struct, so value semantics apply. This means that here, you made a copy of each item in data.pairs:

var pair = data?.pairs[index]

And you are changing the copies, not the originals.

One way to solve this is to assign the changed copies back to data.pairs:

if /* some test */ {
   print ("Found match")
   pair?.setValue(Point(1,2))
   data?.pairs[index] = pair // here!
}

Or, don't make a copy in the first place:

if /* some test */ {
   print ("Found match")
   data?.pairs[index].setValue(Point(1,2))
}

Or, make Pair a class, so reference semantics apply, and you won't be making copies.

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

4 Comments

or simply data?.pairs[index].value = Point(1, 2)
Thanks @Sweeper for your detailed explanation. I have a followed up question. So I have an array to keep track of all the Data (a struct) that i want to modify. When I do 'myArray.append(Data)' , i think all the elements in the 'myArray' is making a copy of the Data. So when I iterate the myArray and make changes to 'Data', it is also making a copy. How can I store reference of Data when append to an array (myArray)?
@hap497 If you modify the data without taking it out of the array, like dataArray[index1].pairs[index2].value = ..., then you won't be making a copy. It's only when you put a struct on the right of =, or when you pass it into a function that you'll be copying it. If you keep it on the left, then you'll be fine. Alternatively, apply the first approach I showed, and copy whatever you copied, back to the data array.
@hap497 If you want to store references though, just make Data a class.
0

As we know, arrays and structs in Swift are value types, so at the moment

var pair = data?.pairs[index]

the pair is a copy of an array item value, and has no relation to the original array.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.