SwiftUI如何在更新已发布数组中的对象而不是数组本身时更新视图
Posted
技术标签:
【中文标题】SwiftUI如何在更新已发布数组中的对象而不是数组本身时更新视图【英文标题】:SwiftUI how to update a view when the object in a published array is updated and not the array itself 【发布时间】:2020-07-29 14:49:01 【问题描述】:以下是我面临的问题的人为示例。
情况: 我有一个类 PersonStore,它将类 Person 存储在一个数组中并已发布。 Person 类为每个 Person 创建一个 LegalAge 模型,该模型已发布 问题: 当更新 LegalAge 中的人员年龄时,不会更新 PersonStore 的视图。
我猜测没有变化的原因是因为变化发生在数组中的对象而不是数组本身。我该如何克服这个问题?
import SwiftUI
enum LegalAge: Int, CaseIterable
case UK = 18
case USA = 21
var name: String "\(self)"
struct ContentView: View
var body: some View
MainView()
/// Displays a list of people and their ages
struct MainView: View
@ObservedObject var personStore = PersonStore()
@State private var addPerson = false
var body: some View
NavigationView
List
ForEach(personStore.store) person in
NavigationLink(destination: ShowAge(person: person))
HStack
Text("\(person.name)")
Text("\(person.model.personsAge)")
Text("\(person.model.country)")
Image(systemName: (person.model.personsAge >= person.model.drinkingAge) ? "checkmark.shield.fill" : "xmark.shield.fill").foregroundColor((person.model.personsAge >= person.model.drinkingAge) ? Color.green : Color.red)
.navigationBarTitle(Text("Can I Drink?"))
.navigationBarItems(leading: Button(action: addPerson = true ) Image(systemName: "plus")
)
/// Open a sheet to create a new person.
.sheet(isPresented: $addPerson) AddPerson().environmentObject(personStore)
/// A Person store to hold all the people.
class PersonStore: ObservableObject
@Published var store = [Person]()
func addPerson(person: Person)
store.append(person)
func getPerson(name: String) -> Person?
if let nameAtIndex = store.firstIndex(where: $0.name == name)
return store[nameAtIndex]
return nil
func insertPerson(person: Person)
store.append(person)
/// Form to allow adding people.
struct AddPerson: View
@EnvironmentObject var personStore: PersonStore
@State private var name: String = ""
@State private var age: String = ""
@State private var country: LegalAge = LegalAge.UK
var body: some View
NavigationView
Form
TextField("Name", text: $name)
TextField("Age", text: $age)
Picker(selection: $country, label: Text("Country"))
ForEach(LegalAge.allCases, id: \.self) c in
Text("\(c.name)").tag(c)
Section
Button(action: personStore.addPerson(person: Person(name: name, age: Int(age) ?? 18, country: country)), label: Text("Add person" ))
/// View to show peoples details and allow some of these details to be edited.
struct ShowAge: View
@ObservedObject var person: Person
@State private var showAgeEditor = false
var body: some View
VStack
/// Show the current age.
Text("\(self.person.name)")
Text("\(self.person.model.personsAge)")
Text("\(self.person.model.country)")
Image(systemName: "keyboard")
.onTapGesture
self.showAgeEditor = true
/// Present the sheet to update the age.
.sheet(isPresented: $showAgeEditor)
SheetView(showAgeEditor: self.$showAgeEditor)
.environmentObject(self.person)
.frame(minWidth: 300, minHeight: 400)
/// Sheet to allow editing of persons details.
struct SheetView: View
@EnvironmentObject var person: Person
@Binding var showAgeEditor: Bool
let maxAge = 21
let minAge = 16
var body: some View
return VStack(alignment: .leading)
Text("Name: \(person.name)")
Stepper(value: $person.model.personsAge, in: minAge...maxAge, step: 1)
Text("Age: \(person.model.personsAge)")
Text("Country: \(person.model.country)")
/// ViewModel that creates the Person Object to stored.
class Person: ObservableObject, Identifiable
@Published var model: LegalDrinkingAge
var name: String
var id = UUID()
init(name: String, age:Int, country: LegalAge)
self.name = name
self.model = Person.createLegalAge(drinkingAge: country.rawValue, country: "\(country)", personsAge: age)
private static func createLegalAge(drinkingAge: Int, country: String, personsAge: Int) -> LegalDrinkingAge
LegalDrinkingAge(drinkingAge: drinkingAge, country: country, personsAge: personsAge)
func updateAge(_ age: Int)
model.personsAge = age
struct LegalDrinkingAge
var drinkingAge: Int = 0
var country: String = ""
var personsAge: Int = 0
mutating func setDrinkingAge(age: Int, country: String, personsAge: Int)
drinkingAge = age
self.country = country
self.personsAge = personsAge
【问题讨论】:
【参考方案1】:分离视图并为人观察
class StorePersonRowView: View
@ObservedObject person: Person
var body: some View
HStack
Text("\(person.name)")
Text("\(person.model.personsAge)")
Text("\(person.model.country)")
Image(systemName: (person.model.personsAge >= person.model.drinkingAge) ? "checkmark.shield.fill" : "xmark.shield.fill").foregroundColor((person.model.personsAge >= person.model.drinkingAge) ? Color.green : Color.red)
并在链接中使用它
ForEach(personStore.store) person in
NavigationLink(destination: ShowAge(person: person))
StorePersonRowView(person: person)
【讨论】:
以上是关于SwiftUI如何在更新已发布数组中的对象而不是数组本身时更新视图的主要内容,如果未能解决你的问题,请参考以下文章