Post

Replies

Boosts

Views

Activity

Updating ObservableObject from multiple views
My goal is to have multiple views with a two-way binding to the same variable. I have created a view with two embedded views that all update the same ObservableObject. However, when one view updates it, only that view can see the change. None of the others get updated. The code compiles just fine, but the views act as if they each have a local variable instead of sharing a published one.What have I missed in how to make this work?import SwiftUI class UserSettings: ObservableObject { @Published var score:Int = 0 } struct ButtonOne: View { @ObservedObject var settings = UserSettings() var body: some View { HStack { Button(action: { self.settings.score += 1 }) { Text("Increase Score") } Text("In ButtonOne your score is \(settings.score)") } } } struct ButtonTwo: View { @ObservedObject var settings = UserSettings() var body: some View { HStack { Button(action: { self.settings.score -= 1 }) { Text("Decrease Score") } Text("In ButtonTwo your score is \(settings.score)") } } } struct ContentView: View { @ObservedObject var settings = UserSettings() var body: some View { VStack(spacing: 10) { Text("In master view your score is \(settings.score)") ButtonOne() ButtonTwo() Text("All scores refer to the same variable, so should be the same.") } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
8
1
12k
Jan ’20
Picker count not updating when array changes
I have created two pickers, one Category picker, and one Item picker, in separate views. Based on excellent input in an earlier question, my Category picker now successfully filters Items in the Item picker and selects the first Item in the selected Category.On the surface, everything looks OK, but the count of items in the Item picker doesn't update after I select a new Category. It retains the count from the originally initialized Category even though the array it is based on now has more items in it.Image and Video of below app and issue can be found here:https://imgur.com/a/eqyrgbFIs there some syntax issue I am overlooking, or am I approaching it completely wrong?/* Situation: Two pickers, one selecting a category and the other selecting the items in that category. Challenge: The second picker shows the right items, but with the Count from the first category. To see issue, copy below code into ContentView on a single-view app. */ import SwiftUI struct Item: Identifiable { var id = UUID() var category:String var item:String } let myCategories:[String] = ["Category 1","Category 2"] let myItems:[Item] = [ Item(category: "Category 1", item: "Item 1.1"), Item(category: "Category 1", item: "Item 1.2"), Item(category: "Category 2", item: "Item 2.1"), Item(category: "Category 2", item: "Item 2.2"), Item(category: "Category 2", item: "Item 2.3"), Item(category: "Category 2", item: "Item 2.4"), ] class MyObject: ObservableObject { // Select Category variables @Published var selectedCategory:String = myCategories[0] @Published var selectedCategoryItems:[Item] = [] @Published var selectedCategoryInt:Int = 0 { didSet { selectCategoryActions(selectedCategoryInt) } } // Select Item variables @Published var selectedItem:Item = myItems[0] @Published var selectedItemInt:Int = 0 { didSet { selectedItem = selectedCategoryItems[selectedItemInt] } } // Initialize values init() { selectCategoryActions(selectedCategoryInt) } // Actions when selecting a new category func selectCategoryActions(_ selectedCategoryInt:Int) { selectedCategory = myCategories[selectedCategoryInt] // Get items in category selectedCategoryItems = myItems.filter{ $0.category.contains(selectedCategory)} // Select item in category let selectedItemIntWrapped:Int? = myItems.firstIndex { $0.category == selectedCategory } if let selectedItemInt = selectedItemIntWrapped { self.selectedItem = myItems[selectedItemInt] } } } // Picker for selecting a category struct SelectCategory: View { var myCategories:[String] @Binding var selectedCategoryInt:Int var body: some View { VStack { Picker(selection: self.$selectedCategoryInt, label: Text("Select category")) { ForEach(0 ..< self.myCategories.count, id: \.self) { Text("\(self.myCategories[$0])") } }.labelsHidden() } } } // Picker for selecting items within the category struct SelectItem: View { var selectedCategoryItems:[Item] @Binding var selectedItemInt:Int var body: some View { VStack { // MARK: Something is going wrong here. I don't get right Item ID's Picker(selection: self.$selectedItemInt, label: Text("Select item")) { ForEach(0 ..< self.selectedCategoryItems.count, id: \.self) { Text("\(self.selectedCategoryItems[$0].item)") } /*ForEach(selectedCategoryItems, id: \.id) { item in Text("\(item.content)") }*/ }.labelsHidden() } } } struct ContentView: View { @ObservedObject var myObject = MyObject() var body: some View { VStack(alignment: .center, spacing: 10) { Text("When selecting Category 2, only two of the four items are shown.") Text("Selected category: \(myObject.selectedCategory)") Text("Items in category: \(myObject.selectedCategoryItems.count)") Text("Selected item: \(myObject.selectedItem.item)") SelectCategory( myCategories: myCategories, selectedCategoryInt: self.$myObject.selectedCategoryInt) SelectItem( selectedCategoryItems: self.myObject.selectedCategoryItems, selectedItemInt: self.$myObject.selectedItemInt) Spacer() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
4
0
3.4k
Jan ’20
Picker count not updating when Array is re-filtered
I have a Category Picker and an Item Picker. When picking a category, it filters the items you can see in the Item picker. Based on excellent input earlier in this Forum, I've managed to get it to work with one small caveat: The count of items doesn't change when you change category.Have I made a syntax error somewhere, or is my approach completely wrong?import SwiftUI // Data struct Item: Identifiable { var id = UUID() var category:String var item:String } let myCategories:[String] = ["Category 1","Category 2"] let myItems:[Item] = [ Item(category: "Category 1", item: "Item 1.1"), Item(category: "Category 1", item: "Item 1.2"), Item(category: "Category 2", item: "Item 2.1"), Item(category: "Category 2", item: "Item 2.2"), Item(category: "Category 2", item: "Item 2.3"), Item(category: "Category 2", item: "Item 2.4"), ] // Factory class MyObject: ObservableObject { // Category picker variables @Published var selectedCategory:String = myCategories[0] @Published var selectedCategoryItems:[Item] = [] @Published var selectedCategoryInt:Int = 0 { didSet { selectCategoryActions(selectedCategoryInt) } } // Item picker variables @Published var selectedItem:Item = myItems[0] @Published var selectedItemInt:Int = 0 { didSet { selectedItem = selectedCategoryItems[selectedItemInt] } } // Initial category selection init() { selectCategoryActions(selectedCategoryInt) } // Actions when selecting a new category func selectCategoryActions(_ selectedCategoryInt:Int) { selectedCategory = myCategories[selectedCategoryInt] // Get items in category selectedCategoryItems = myItems.filter{ $0.category.contains(selectedCategory)} // Select initial item in category let selectedItemIntWrapped:Int? = myItems.firstIndex { $0.category == selectedCategory } if let selectedItemInt = selectedItemIntWrapped { self.selectedItem = myItems[selectedItemInt] } } } // View struct ContentView: View { @ObservedObject var myObject = MyObject() var body: some View { VStack(spacing: 10) { Section(header: Text("Observable Object")) { Text("Category 2 has four items, but only the first two are shown.") Text("Selected category: \(myObject.selectedCategory)") Text("Items in category: \(myObject.selectedCategoryItems.count)") Text("Selected item: \(myObject.selectedItem.item)") Picker(selection: self.$myObject.selectedCategoryInt, label: Text("Select category")) { ForEach(0 ..< myCategories.count, id: \.self) { Text("\(myCategories[$0])") } }.labelsHidden() // MARK: Something is going wrong here. The count doesn't update after picking a new category. Picker(selection: self.$myObject.selectedItemInt, label: Text("Select object item")) { ForEach(0 ..< self.myObject.selectedCategoryItems.count, id: \.self) { Text("\(self.myObject.selectedCategoryItems[$0].item)") } /*ForEach(selectedCategoryItems, id: \.id) { item in Text("\(item.content)") }*/ }.labelsHidden() } Spacer() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
0
0
531
Jan ’20