@EnvironmentObject 属性 在 swiftUI 中无法正常工作
@EnvironmentObject property not working properly in swiftUI
从 ViewModel 更新 cartArray 不会追加到当前元素,而是每次都会重新添加对象。我需要将 cartArray 维护为全局数组,以便可以从项目的任何视图访问它。我正在从 ViewModel 向 cartArray 添加元素。我使用了一个单独的 class DataStorage,它具有可以通过整个项目访问的对象
Example_AppApp.swift
import SwiftUI
@main
struct Example_AppApp: App {
var body: some Scene {
WindowGroup {
ContentView().environmentObject(DataStorage())
}
}
}
DataStorage.swift
import Foundation
class DataStorage: ObservableObject {
@Published var cartArray = [Book]()
}
ContentView.swift
import SwiftUI
struct ContentView: View {
@State var showSheetView = false
var body: some View {
NavigationView{
ListViewDisplay()
.navigationBarItems(trailing:
Button(action: {
self.showSheetView.toggle()
}) {
Image(systemName: "cart.circle.fill")
.font(Font.system(.title))
}
)
}.sheet(isPresented: $showSheetView) {
View3()
}
}
}
struct ListViewDisplay: View{
var book = [
Book(bookId: 1 ,bookName: "Catch-22"),
Book(bookId: 2 ,bookName: "Just-Shocking" ),
Book(bookId: 3 ,bookName: "Stephen King" ),
Book(bookId: 4,bookName: "A Gentleman in Moscow"),
]
var body: some View {
List(book, id: \.id) { book in
Text(book.bookName)
NavigationLink(destination: View1(book: book)) {
}
}
}
}
View1Modal.swift
import Foundation
struct Book: Codable, Identifiable {
var id:String{bookName}
var bookId : Int
var bookName: String
}
struct BookOption: Codable{
var name: String
var price: Int
}
View1ViewModel.swift
import Foundation
import Combine
class View1ViewModel : ObservableObject{
var dataStorage = DataStorage()
func addBook (bookId:Int ,bookName : String){
dataStorage.cartArray.append(Book(bookId:bookId, bookName: bookName)) // Adding to global array
print(dataStorage.cartArray)
}
}
View1.swift
import SwiftUI
struct View1: View {
@ObservedObject var vwModel = View1ViewModel()
@EnvironmentObject var datastrg: DataStorage
var book:Book
var body: some View {
Text(book.bookName).font(.title)
Spacer()
Button(action: {
vwModel.addBook(bookId: book.bookId, bookName: book.bookName)
}, label: {
Text("Add Book to Cart")
.frame(maxWidth: .infinity, minHeight: 60)
.background(Color.red)
.foregroundColor(Color.white)
.font(.custom("OpenSans-Bold", size: 24))
})
}
}
View3.swift
import SwiftUI
struct View3: View {
@EnvironmentObject var datastorage : DataStorage
var body: some View {
NavigationView {
List(datastorage.cartArray,id:\.id){book in
VStack{
Text(book.bookName)
.font(.custom("OpenSans-Bold", size: 20))
}
}
.navigationBarTitle(Text("Cart"), displayMode: .inline)
}
}
}
当第一次调用 addBook 函数时,它打印为
[Example_App.Book(bookId: 1, bookName: "Catch-22")]
当我返回此 View1 并通过调用 addBook
添加另一本书时 func
它作为新对象添加到 cartArray
[Example_App.Book(bookId: 3, bookName: "Stephen King")]
打印 cartArray
中的元素数量给出 1 element
而不是 2 elements
。当我转到 View3
并在列表中显示图书时,cartArray
显示为 empty(0 elements)
我认为 ViewModel class 中的 var dataStorage = DataStorage() 有问题。每次这是新创建的,所以不会存储 prevoius 值。但我不明白如何保持它的状态
如何在 View3 中显示列表?任何想法/建议都会有所帮助
您没有在任何地方调用您的函数 addBook,在调用该函数的 view3 中添加一个 onappear,您的列表将填充数据。
您需要 DataStorage
的一个实例 被传递。任何时候你写 DataStorage()
都会创建一个 新实例 .
.environmentObject
将允许您将该实例注入视图层次结构。然后,您可以使用 @EnvironmentObject
属性 包装器在 View
.
中访问它
在 View1
中,我使用 onAppear
将 dataStorage
属性 设置为 View1ViewModel
-- 这意味着它必须是可选的View1ViewModel
因为它不会在 init
中设置。我避免在 init
中设置它的原因是因为 @EnvironmentObject
没有设置为 View
的 init
-- 它在渲染时被注入。
@main
struct Example_AppApp: App {
var dataStorage = DataStorage()
var body: some Scene {
WindowGroup {
ContentView().environmentObject(dataStorage)
}
}
}
class DataStorage: ObservableObject {
@Published var cartArray = [Book]()
}
struct ContentView: View {
@State var showSheetView = false
var body: some View {
NavigationView{
ListViewDisplay()
.navigationBarItems(trailing:
Button(action: {
self.showSheetView.toggle()
}) {
Image(systemName: "cart.circle.fill")
.font(Font.system(.title))
}
)
}.sheet(isPresented: $showSheetView) {
View3()
}
}
}
struct ListViewDisplay: View {
var book = [
Book(bookId: 1 ,bookName: "Catch-22"),
Book(bookId: 2 ,bookName: "Just-Shocking" ),
Book(bookId: 3 ,bookName: "Stephen King" ),
Book(bookId: 4,bookName: "A Gentleman in Moscow"),
]
var body: some View {
List(book, id: \.id) { book in
Text(book.bookName)
NavigationLink(destination: View1(book: book)) {
}
}
}
}
struct Book: Codable, Identifiable {
var id:String{bookName}
var bookId : Int
var bookName: String
}
struct BookOption: Codable{
var name: String
var price: Int
}
class View1ViewModel : ObservableObject{
var dataStorage : DataStorage?
func addBook (bookId:Int ,bookName : String) {
guard let dataStorage = dataStorage else {
fatalError("DataStorage not set")
}
dataStorage.cartArray.append(Book(bookId:bookId, bookName: bookName)) // Adding to global array
print(dataStorage.cartArray)
}
}
struct View1: View {
@ObservedObject var vwModel = View1ViewModel()
@EnvironmentObject var datastrg: DataStorage
var book:Book
var body: some View {
Text(book.bookName).font(.title)
Spacer()
Button(action: {
vwModel.addBook(bookId: book.bookId, bookName: book.bookName)
}, label: {
Text("Add Book to Cart")
.frame(maxWidth: .infinity, minHeight: 60)
.background(Color.red)
.foregroundColor(Color.white)
.font(.custom("OpenSans-Bold", size: 24))
})
.onAppear {
vwModel.dataStorage = datastrg
}
}
}
struct View3: View {
@EnvironmentObject var datastorage : DataStorage
var body: some View {
NavigationView {
List(datastorage.cartArray,id:\.id){book in
VStack{
Text(book.bookName)
.font(.custom("OpenSans-Bold", size: 20))
}
}
.navigationBarTitle(Text("Cart"), displayMode: .inline)
}
}
}
从 ViewModel 更新 cartArray 不会追加到当前元素,而是每次都会重新添加对象。我需要将 cartArray 维护为全局数组,以便可以从项目的任何视图访问它。我正在从 ViewModel 向 cartArray 添加元素。我使用了一个单独的 class DataStorage,它具有可以通过整个项目访问的对象
Example_AppApp.swift
import SwiftUI
@main
struct Example_AppApp: App {
var body: some Scene {
WindowGroup {
ContentView().environmentObject(DataStorage())
}
}
}
DataStorage.swift
import Foundation
class DataStorage: ObservableObject {
@Published var cartArray = [Book]()
}
ContentView.swift
import SwiftUI
struct ContentView: View {
@State var showSheetView = false
var body: some View {
NavigationView{
ListViewDisplay()
.navigationBarItems(trailing:
Button(action: {
self.showSheetView.toggle()
}) {
Image(systemName: "cart.circle.fill")
.font(Font.system(.title))
}
)
}.sheet(isPresented: $showSheetView) {
View3()
}
}
}
struct ListViewDisplay: View{
var book = [
Book(bookId: 1 ,bookName: "Catch-22"),
Book(bookId: 2 ,bookName: "Just-Shocking" ),
Book(bookId: 3 ,bookName: "Stephen King" ),
Book(bookId: 4,bookName: "A Gentleman in Moscow"),
]
var body: some View {
List(book, id: \.id) { book in
Text(book.bookName)
NavigationLink(destination: View1(book: book)) {
}
}
}
}
View1Modal.swift
import Foundation
struct Book: Codable, Identifiable {
var id:String{bookName}
var bookId : Int
var bookName: String
}
struct BookOption: Codable{
var name: String
var price: Int
}
View1ViewModel.swift
import Foundation
import Combine
class View1ViewModel : ObservableObject{
var dataStorage = DataStorage()
func addBook (bookId:Int ,bookName : String){
dataStorage.cartArray.append(Book(bookId:bookId, bookName: bookName)) // Adding to global array
print(dataStorage.cartArray)
}
}
View1.swift
import SwiftUI
struct View1: View {
@ObservedObject var vwModel = View1ViewModel()
@EnvironmentObject var datastrg: DataStorage
var book:Book
var body: some View {
Text(book.bookName).font(.title)
Spacer()
Button(action: {
vwModel.addBook(bookId: book.bookId, bookName: book.bookName)
}, label: {
Text("Add Book to Cart")
.frame(maxWidth: .infinity, minHeight: 60)
.background(Color.red)
.foregroundColor(Color.white)
.font(.custom("OpenSans-Bold", size: 24))
})
}
}
View3.swift
import SwiftUI
struct View3: View {
@EnvironmentObject var datastorage : DataStorage
var body: some View {
NavigationView {
List(datastorage.cartArray,id:\.id){book in
VStack{
Text(book.bookName)
.font(.custom("OpenSans-Bold", size: 20))
}
}
.navigationBarTitle(Text("Cart"), displayMode: .inline)
}
}
}
当第一次调用 addBook 函数时,它打印为
[Example_App.Book(bookId: 1, bookName: "Catch-22")]
当我返回此 View1 并通过调用 addBook
添加另一本书时 func
它作为新对象添加到 cartArray
[Example_App.Book(bookId: 3, bookName: "Stephen King")]
打印 cartArray
中的元素数量给出 1 element
而不是 2 elements
。当我转到 View3
并在列表中显示图书时,cartArray
显示为 empty(0 elements)
我认为 ViewModel class 中的 var dataStorage = DataStorage() 有问题。每次这是新创建的,所以不会存储 prevoius 值。但我不明白如何保持它的状态 如何在 View3 中显示列表?任何想法/建议都会有所帮助
您没有在任何地方调用您的函数 addBook,在调用该函数的 view3 中添加一个 onappear,您的列表将填充数据。
您需要 DataStorage
的一个实例 被传递。任何时候你写 DataStorage()
都会创建一个 新实例 .
.environmentObject
将允许您将该实例注入视图层次结构。然后,您可以使用 @EnvironmentObject
属性 包装器在 View
.
在 View1
中,我使用 onAppear
将 dataStorage
属性 设置为 View1ViewModel
-- 这意味着它必须是可选的View1ViewModel
因为它不会在 init
中设置。我避免在 init
中设置它的原因是因为 @EnvironmentObject
没有设置为 View
的 init
-- 它在渲染时被注入。
@main
struct Example_AppApp: App {
var dataStorage = DataStorage()
var body: some Scene {
WindowGroup {
ContentView().environmentObject(dataStorage)
}
}
}
class DataStorage: ObservableObject {
@Published var cartArray = [Book]()
}
struct ContentView: View {
@State var showSheetView = false
var body: some View {
NavigationView{
ListViewDisplay()
.navigationBarItems(trailing:
Button(action: {
self.showSheetView.toggle()
}) {
Image(systemName: "cart.circle.fill")
.font(Font.system(.title))
}
)
}.sheet(isPresented: $showSheetView) {
View3()
}
}
}
struct ListViewDisplay: View {
var book = [
Book(bookId: 1 ,bookName: "Catch-22"),
Book(bookId: 2 ,bookName: "Just-Shocking" ),
Book(bookId: 3 ,bookName: "Stephen King" ),
Book(bookId: 4,bookName: "A Gentleman in Moscow"),
]
var body: some View {
List(book, id: \.id) { book in
Text(book.bookName)
NavigationLink(destination: View1(book: book)) {
}
}
}
}
struct Book: Codable, Identifiable {
var id:String{bookName}
var bookId : Int
var bookName: String
}
struct BookOption: Codable{
var name: String
var price: Int
}
class View1ViewModel : ObservableObject{
var dataStorage : DataStorage?
func addBook (bookId:Int ,bookName : String) {
guard let dataStorage = dataStorage else {
fatalError("DataStorage not set")
}
dataStorage.cartArray.append(Book(bookId:bookId, bookName: bookName)) // Adding to global array
print(dataStorage.cartArray)
}
}
struct View1: View {
@ObservedObject var vwModel = View1ViewModel()
@EnvironmentObject var datastrg: DataStorage
var book:Book
var body: some View {
Text(book.bookName).font(.title)
Spacer()
Button(action: {
vwModel.addBook(bookId: book.bookId, bookName: book.bookName)
}, label: {
Text("Add Book to Cart")
.frame(maxWidth: .infinity, minHeight: 60)
.background(Color.red)
.foregroundColor(Color.white)
.font(.custom("OpenSans-Bold", size: 24))
})
.onAppear {
vwModel.dataStorage = datastrg
}
}
}
struct View3: View {
@EnvironmentObject var datastorage : DataStorage
var body: some View {
NavigationView {
List(datastorage.cartArray,id:\.id){book in
VStack{
Text(book.bookName)
.font(.custom("OpenSans-Bold", size: 20))
}
}
.navigationBarTitle(Text("Cart"), displayMode: .inline)
}
}
}