В Списке. Левая сторона мутирующего оператора не изменяема: «элемент» — это константа «пусть».

#swift #xcode #list #swiftui #mutable

Вопрос:

Xcode 12. Код и жизненный цикл являются быстрыми.

Я посмотрел на вопросы, связанные с другими людьми, и мне кажется, что они просто выкладывают здесь весь свой код проектов; немного сложно выбрать из него то, что мне нужно. Итак, я разбил проблему на самый простой пример, который я могу.

Цель состоит в том, чтобы число X повторялось, когда я нажимаю кнопку .

Заранее спасибо!

 struct InfoData: Identifiable {  var id = UUID()  var nameX: String  var numberX: Int }  class ContentX: ObservableObject {  @Published var infoX = [  InfoData(nameX: "Example", numberX: 1)  ] }  struct ContentView: View {  @StateObject var contentX = ContentX()  var body: some View {  List(contentX.infoX) { item in  HStack {  Text("(item.nameX)")  Spacer()  Button(" ") {  item.numberX  = 1 //Eror shows up here <<  }  Text("(item.numberX)")  }  }  } }  

Комментарии:

1. Вызовите contentX и попросите его напрямую обновить массив infoX требуемым значением.

Ответ №1:

В синтаксисе, который вы используете, item это неизменяемое значение, как сообщает вам ошибка. Вы не можете изменить его, потому что он не представляет собой истинное соединение с массивом, из которого он получен, — это просто временная читаемая копия, используемая в List итерации.

Если вы можете перейти на Xcode 13, у вас будет доступ к так называемому синтаксису привязки элементов List , и ForEach это позволит вам сделать это:

 struct ContentView: View {  @StateObject var contentX = ContentX()  var body: some View {  List($contentX.infoX) { $item in //<-- Here  HStack {  Text("(item.nameX)")  Spacer()  Button(" ") {  item.numberX  = 1  }  Text("(item.numberX)")  }  }  } }  

Это дает вам Binding возможность item изменять значение, позволяя изменять его значения и отражать их в исходном массиве.

До Xcode 13/Swift 5.5 вам нужно было бы определить свой собственный способ изменения элемента в массиве. Это одно из решений:

 class ContentX: ObservableObject {  @Published var infoX = [  InfoData(nameX: "Example", numberX: 1)  ]    func alterItem(item: InfoData) {  self.infoX = self.infoX.map { $0.id == item.id ? item : $0 }  } }  struct ContentView: View {  @StateObject var contentX = ContentX()  var body: some View {  List(contentX.infoX) { item in  HStack {  Text("(item.nameX)")  Spacer()  Button(" ") {  var newItem = item  newItem.numberX  = 1  contentX.alterItem(item: newItem)  }  Text("(item.numberX)")  }  }  } }  

Или другой вариант, в котором используется пользовательский Binding :

  class ContentX: ObservableObject {  @Published var infoX = [  InfoData(nameX: "Example", numberX: 1)  ]    func bindingForItem(item: InfoData) -> Binding<InfoData> {  .init {  self.infoX.first { $0.id == item.id }!  } set: { newValue in  self.infoX = self.infoX.map { $0.id == item.id ? newValue : $0 }  }  } }  struct ContentView: View {  @StateObject var contentX = ContentX()  var body: some View {  List(contentX.infoX) { item in  HStack {  Text("(item.nameX)")  Spacer()  Button(" ") {  contentX.bindingForItem(item: item).wrappedValue.numberX  = 1  }  Text("(item.numberX)")  }  }  } }  

Комментарии:

1. Большое вам спасибо! Я совершенно новичок в коде, поэтому иногда я просто еще не понял, как все работает. Я с нетерпением жду Xcode 13, но сейчас я нахожусь в середине курса, и я беспокоюсь, что не смогу следить за ним, если обновлю. Хотя, возможно, мой страх необоснован.

2. Да, неплохая идея, чтобы все было удобно, пока ты учишься.