Swift - как мутировать объект struct при итерации по нему
Я все еще не уверен в правилах структурной копии или ссылки.
Я хочу мутировать объект struct во время итерации по нему из массива:
Например, в этом случае я хотел бы изменить цвет фона
но компилятор кричит на меня
struct Options {
var backgroundColor = UIColor.blackColor()
}
var arrayOfMyStruct = [MyStruct]
...
for obj in arrayOfMyStruct {
obj.backgroundColor = UIColor.redColor() // ! get an error
}
Ответы
Ответ 1
struct
являются типами значений, поэтому в цикле for
вы имеете дело с копией.
В качестве теста вы можете попробовать следующее:
Swift 3:
struct Options {
var backgroundColor = UIColor.black
}
var arrayOfMyStruct = [Options]()
for (index, _) in arrayOfMyStruct.enumerated() {
arrayOfMyStruct[index].backgroundColor = UIColor.red
}
Swift 2:
struct Options {
var backgroundColor = UIColor.blackColor()
}
var arrayOfMyStruct = [Options]()
for (index, _) in enumerate(arrayOfMyStruct) {
arrayOfMyStruct[index].backgroundColor = UIColor.redColor()
}
Здесь вы просто перечисляете индекс и напрямую получаете значение, хранящееся в массиве.
Надеюсь, что это поможет.
Ответ 2
Вы можете использовать Array.indices
:
for index in arrayOfMyStruct.indices {
arrayOfMyStruct[index].backgroundColor = UIColor.red
}
Ответ 3
Для Swift 3 используйте метод enumerated()
.
Например:
for (index, _) in arrayOfMyStruct.enumerated() {
arrayOfMyStruct[index].backgroundColor = UIColor.redColor()
}
Кортеж также включает в себя копию объекта, так что вместо этого вы можете использовать for (index, object)
для непосредственного доступа к объекту, но, поскольку он является копией, вы не сможете изменять массив таким образом, и вам следует использовать index
для этого. Чтобы напрямую процитировать документацию:
Если вам нужен целочисленный индекс каждого элемента, а также его значение, используйте метод enumerated() для перебора массива. Для каждого элемента в массиве метод enumerated() возвращает кортеж, состоящий из целого числа и элемента.
Ответ 4
Вы работаете с struct
объектов, которые копируются в локальную переменную при использовании for in
цикле. Также массив - это объект struct
, поэтому, если вы хотите изменить все члены массива, вы должны создать модифицированную копию исходного массива, заполненную модифицированными копиями оригинальных объектов.
arrayOfMyStruct = arrayOfMyStruct.map { obj in
var obj = obj
obj.backgroundColor = .red
return obj
}
Это можно упростить, добавив это расширение Array.
Swift 4
extension Array {
mutating func mutateEach(by transform: (inout Element) throws -> Void) rethrows {
self = try map { el in
var el = el
try transform(&el)
return el
}
}
}
использование
arrayOfMyStruct.mutateEach { obj in
obj.backgroundColor = .red
}
Ответ 5
В настоящее время есть лучшее решение:
for index in arrayOfMyStruct.indices {
arrayOfMyStruct[index].backgroundColor = .redColor
}
Документы: https://developer.apple.com/documentation/swift/collection/1641719-indices
Ответ 6
Я видел этот метод в некотором коде и, похоже, работает
for (var mutableStruct) in arrayOfMyStruct {
mutableStruct.backgroundColor = UIColor.redColor()
}