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
}

Ответ 6

Я видел этот метод в некотором коде и, похоже, работает

for (var mutableStruct) in arrayOfMyStruct {
  mutableStruct.backgroundColor = UIColor.redColor()
}