Я пытаюсь создать представление, которое обновляется в зависимости от того, переключает ли пользователь кнопку избранного или нет. Я хочу, чтобы все представление реконструировалось, чтобы отображать массив значений всякий раз, когда этот массив значений изменяется. Внутри представления цикл for each должен отображать каждое значение в массиве.
Представление, которое я хочу обновлять каждый раз, когда изменяется saveArray, — это FavView. Но когда я пытаюсь использовать цикл foreach для отображения каждого значения, это saveArray (которое я создал как @Published, чтобы представление реконструировалось), это дает мне ошибку. Общая структура «ForEach» требует, чтобы «Published <[String]>. Издатель» соответствует «RandomAccessCollection». Я сбит с толку, потому что думал, что массивы String можно использовать для каждого цикла. Разве это не правда? Как пройтись по массиву @Published? Спасибо! Это мой код для сохраненного массива (в ViewModel) и FavView, в котором я хочу отобразить его, для каждого.
struct ContentView: View {
@StateObject private var statNavManager = StatsNavigationManager()
@State private var saved: [String] = []
var body: some View {
TabView {
StatsView(saved: $saved)
.tabItem {
Label("Home", systemImage: "house")
}
FavView(saved: $saved)
.tabItem {
Label("Saved", systemImage: "bookmark")
}
}
.environmentObject(statNavManager)
}
}
final class ViewModel: ObservableObject {
@Published var items = [Item]()
@Published var showingFavs = true
@Published var savedItems: Set<String> = []
@Published var savedArray: [String]
// Filter saved items
var filteredItems: [String] {
//return self.items
return savedArray
}
var db = Database()
init() {
self.savedItems = db.load()
self.items = db.returnList()//the items
self.savedArray = Array(db.load())
print("savedarray", savedArray)
print("important!", self.savedItems, self.items)
}
func contains(_ item: Item) -> Bool {
savedItems.contains(item.id)
}
// Toggle saved items
func toggleFav(item: Item) {
print("Toggled!", item)
if contains(item) {
savedItems.remove(item.id)
if let index = savedArray.firstIndex(of: item.id) {
savedArray.remove(at: index)
}
} else {
savedItems.insert(item.id)
savedArray.append(item.id)
}
db.save(items: savedItems)
}
}
struct FavView: View {
@StateObject private var vm = ViewModel()
var body: some View {
VStack {
List {
var x = print("testing",vm.savedArray)//this only prints once at the start
ForEach($vm.savedArray, id: \.self) { string in
let item = vm.db.returnItem(input: string.wrappedValue)
HStack {
VStack(alignment: .leading) {
Text(item.title)
.font(.headline)
Text(item.description)
.font(.subheadline)
}
Spacer()
Image(systemName: vm.contains(item) ? "bookmark.fill" : "bookmark")
.foregroundColor(.blue)
.onTapGesture {
vm.toggleFav(item: item)
}
}
}
}
.cornerRadius(10)
}
}
}





в ForEach вы используете символ $ для доступа к savedArray вам нужно использовать сам vm
struct FavView: View {
@StateObject private var vm = ViewModel()
var body: some View {
VStack {
List {
ForEach($vm.savedArray, id: \.self) { string in //< here $vm.savedArray not vm.$savedArray
let item = vm.db.returnItem(input: string)
HStack {
VStack(alignment: .leading) {
Text(item.title)
.font(.headline)
Text(item.description)
.font(.subheadline)
}
Spacer()
Image(systemName: vm.contains(item) ? "bookmark.fill" : "bookmark")
.foregroundColor(.blue)
.onTapGesture {
vm.toggleFav(item: item)
}
}
}
}
.cornerRadius(10)
}
}
}
это должно работать.
если «Published<[String]>.Publisher» соответствует «RandomAccessCollection». исправлено, пожалуйста, примите мой ответ
поделитесь скриншотом кода с ошибкой, чтобы было понятно
Я исправил проблему, используя .wrappedValue, поэтому мой код теперь работает, но похоже, что настоящая причина, по которой мой код не работает, заключается в том, что даже при том, что saveArray изменен, FavView не инициализируется повторно, когда он изменяется, поэтому он отображает старый значения. Когда я перезапускаю программу, FavView перестраивается. Есть ли способ восстановить FavView всякий раз, когда я редактирую saveArray? Спасибо!
Я только что изменил его, и он дает мне ошибку «Невозможно преобразовать значение типа« Binding <String> »в ожидаемый тип аргумента« String »» в строке vm.db.returnItem(), которая принимает ввод String. Я отредактировал, чтобы включить эту функцию. Спасибо!