Changing The value of struct in an array
Besides what said by @MikeS, remember that structs are value types. So in the for
loop:
for test in testings {
a copy of an array element is assigned to the test
variable. Any change you make on it is restricted to the test
variable, without doing any actual change to the array elements. It works for classes because they are reference types, hence the reference and not the value is copied to the test
variable.
The proper way to do that is by using a for
by index:
for index in 0..<testings.count {
testings[index].value = 15
}
in this case you are accessing (and modifying) the actual struct element and not a copy of it.
Well I am going to update my answer for swift 3 compatibility.
When you are programming many you need to change some values of objects that are inside a collection. In this example we have an array of struct and given a condition we need to change the value of a specific object. This is a very common thing in any development day.
Instead of using an index to determine which object has to be modified I prefer to use an if condition, which IMHO is more common.
import Foundation
struct MyStruct: CustomDebugStringConvertible {
var myValue:Int
var debugDescription: String {
return "struct is \(myValue)"
}
}
let struct1 = MyStruct(myValue: 1)
let struct2 = MyStruct(myValue: 2)
let structArray = [struct1, struct2]
let newStructArray = structArray.map({ (myStruct) -> MyStruct in
// You can check anything like:
if myStruct.myValue == 1 {
var modified = myStruct
modified.myValue = 400
return modified
} else {
return myStruct
}
})
debugPrint(newStructArray)
Notice all the lets, this way of development is safer.
The classes are reference types, it's not needed to make a copy in order to change a value, like it happens with structs. Using the same example with classes:
class MyClass: CustomDebugStringConvertible {
var myValue:Int
init(myValue: Int){
self.myValue = myValue
}
var debugDescription: String {
return "class is \(myValue)"
}
}
let class1 = MyClass(myValue: 1)
let class2 = MyClass(myValue: 2)
let classArray = [class1, class2]
let newClassArray = classArray.map({ (myClass) -> MyClass in
// You can check anything like:
if myClass.myValue == 1 {
myClass.myValue = 400
}
return myClass
})
debugPrint(newClassArray)
To simplify working with value types in arrays you could use following extension (Swift 3):
extension Array {
mutating func modifyForEach(_ body: (_ index: Index, _ element: inout Element) -> ()) {
for index in indices {
modifyElement(atIndex: index) { body(index, &$0) }
}
}
mutating func modifyElement(atIndex index: Index, _ modifyElement: (_ element: inout Element) -> ()) {
var element = self[index]
modifyElement(&element)
self[index] = element
}
}
Example usage:
testings.modifyElement(atIndex: 0) { $0.value = 99 }
testings.modifyForEach { $1.value *= 2 }
testings.modifyForEach { $1.value = $0 }
How to change Array
of Structs
for every element:
itemsArray.indices.forEach { itemsArray[$0].someValue = newValue }
for specific element:
itemsArray.indices.filter { itemsArray[$0].propertyToCompare == true }
.forEach { itemsArray[$0].someValue = newValue }
This is very tricky answer. I think, You should not do like this:
struct testing {
var value:Int
}
var test1 = testing(value: 6)
var test2 = testing(value: 12)
var ary = [UnsafeMutablePointer<testing>].convertFromArrayLiteral(&test1, &test2)
for p in ary {
p.memory.value = 3
}
if test1.value == test2.value {
println("value: \(test1.value)")
}
For Xcode 6.1, array initialization will be
var ary = [UnsafeMutablePointer<testing>](arrayLiteral: &test1, &test2)