我有一个类需要更新全局环境对象。我可以整天在结构之间传递该环境对象,但是如何允许类对象访问同一变量?
import SwiftUI
class Global: ObservableObject
{
@Published var num = 10
}
class MyClass:ObservableObject
{
@Published var mode = 1
@EnvironmentObject var global: Global
func updateMode()
{
self.mode += 1
global.num += 1
}
}
@main
struct MyApp: App
{
let settings = Global()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(settings)
}
}
}
struct ContentView: View
{
@EnvironmentObject var global: Global
@ObservedObject var myClass = MyClass()
var body: some View
{
VStack
{
Text("Setting \(global.num)")
Text("Mode …
Run Code Online (Sandbox Code Playgroud) 我知道EnvironmentObject
属性包装器可用于将对象传递给视图。我有一个会话对象,我正在将其传递给我的视图。现在我需要将其传递到我的模型类之一(即非视图)。理想情况下,该模型(接收会话对象)被实例化为StateObject
.
struct CreditDetailsView: View {
@EnvironmentObject var session: Session
@StateObject var transactionsModel = TransactionsModel(token: session.token)
Run Code Online (Sandbox Code Playgroud)
上面的代码将不起作用(可以理解),因为:
cannot use instance member 'session' within property initializer; property initializers run before 'self' is available
Run Code Online (Sandbox Code Playgroud)
关于如何将会话传递到 的任何建议TransactionsModel
?
这就是崩溃的样子
所以它在 UIKit 线上随机崩溃
UIKitCore
-[UIViewController _ancestorViewControllerOfClass:allowModalParent:] + 44
Run Code Online (Sandbox Code Playgroud)
我在默认的 SwiftUI 导航堆栈中有视图:
struct MyView: View {
@EnvironmentObject var viewModel: MyViewModel
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
var body: some View {
ZStack {
......
}
.onAppear {
self.viewModel
.onViewAppear(presentationMode: self.presentationMode)
}
}
}
final class MyViewModel {
var presentationMode: Binding<PresentationMode>?
func onViewAppear(presentationMode: Binding<PresentationMode>) {
self.presentationMode = presentationMode
}
func hide() {
presentationMode?.wrappedValue.dismiss() // crashes after calling this
}
}
Run Code Online (Sandbox Code Playgroud)
所以我以这种方式将 MyView 推送到导航堆栈中:
NavigationLink(
destination: MyView()
) {
Image(systemName: "plus.circle")
.font(.title)
}
Run Code Online (Sandbox Code Playgroud)
然后在用户在几秒钟后按下 …
presentation-model uinavigationcontroller swift swiftui environmentobject
当我尝试接收的变量是 @EnvironmentObject 的 @Published 属性时,有什么方法可以阻止 onReceive 在视图最初加载时触发?
这是视图:
struct ContentView: View {
@EnvironmentObject var appState: AppState
var body: some View {
VStack {
Text(appState.test)
.padding()
}
.onAppear() {
appState.test = "World"
}
.onReceive(appState.$test) { test in
print("Hello from onReceive: \(test)")
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是环境对象:
public class AppState: ObservableObject {
@Published public var test = "hello"
}
Run Code Online (Sandbox Code Playgroud)
并输出:
Hello from onReceive: hello
Hello from onReceive: World
Run Code Online (Sandbox Code Playgroud)
我猜第一个是在注入环境对象时触发的。有什么方法可以防止这种情况(除了我在 onAppear 中设置的一些 hackish bool 之外)?理想情况下,我只想看到“Hello from onReceive: World”这只是一个简单的例子。在我的实际应用程序中,我正在从 onAppear 中的服务获取数据,在我的环境对象中,我有一个错误状态,当清除该错误状态时,我希望它触发 onReceive 执行一些其他逻辑,然后重新获取。
我一直在阅读 SwiftUI 中的属性包装器,我看到它们做得很好,但我真正不明白的一件事是@EnvironmentObject和@ObservedObject之间的区别。
从我到目前为止所学到的,我看到@EnvironmentObject在我们的应用程序的各个地方都需要一个对象时使用,但我们不需要通过所有这些地方传递它。例如,如果我们有层次结构 A -> B -> C -> D 并且对象是在 A 处创建的,那么它会保存在环境中,以便我们可以将它直接从 A 传递到 D,如果 D 需要的话。
如果我们使用在 A 创建并需要传递给 D 的@ObservedObject,那么我们也需要通过 B 和 C。
但我仍然不知道如何决定使用哪一个。以下是我制作的 2 个示例项目:
struct ContentView2: View {
var order = Order2()
var body: some View {
VStack {
EditView2()
DisplayView2()
}
.environmentObject(order)
}
}
struct EditView2: View {
@EnvironmentObject var user: Order2
var body: some View {
HStack{
TextField("Fruit", text: $user.item)
}
}
}
struct …
Run Code Online (Sandbox Code Playgroud) 我有一个视图,显示用于过滤列表中项目的工作表。该视图有这个变量:
struct JobsTab: View {
@State private var jobFilter: JobFilter = JobFilter()
var filter: some View {
Button {
self.showFilter = true
} label: {
Image(systemName: "line.horizontal.3.decrease.circle")
.renderingMode(.original)
}
.sheet(isPresented: $showFilter) {
FilterView($jobFilter, categoriesViewModel, jobsViewModel)
}
}
Run Code Online (Sandbox Code Playgroud)
但是,在工作表中,我正在尝试以下操作,但单击“完成”按钮时无法关闭视图,只能单击“取消”按钮:
struct FilterView: View {
@Environment(\.presentationMode) var presentationMode
@ObservedObject var categoriesViewModel: CategoriesViewModel
@ObservedObject var jobsViewModel: JobsViewModel
let filterViewModel: FilterViewModel
@Binding var jobFilter: JobFilter
@State private var draft: JobFilter
@State var searchText = ""
init(_ jobFilter: Binding<JobFilter>, _ categoriesViewModel: CategoriesViewModel, _ jobsViewModel: JobsViewModel) { …
Run Code Online (Sandbox Code Playgroud) 我拥有的:View 和 ViewModel(作为 View 结构的扩展)。
它们都使用AppState类型的@EnvironmentObject。
问题是我的预览由于以下错误而崩溃:
Fatal error: No ObservableObject of type AppState found
。
注释掉loadUser
func 中的行可以避免崩溃。
struct ProfileView: View {
@EnvironmentObject var appState: AppState
@ObservedObject var viewModel = ViewModel()
...
}
Run Code Online (Sandbox Code Playgroud)
extension ProfileView {
class ViewModel: ObservableObject {
@EnvironmentObject var appState: AppState
@Published var userVM = UserVM(.example)
init() {
loadUser()
}
func loadUser() {
User.WebService.getSelf { user, errorMsg in
DispatchQueue.main.async {
guard let user = user else {
/*self.appState.showingAlert = true
self.appState.alert = Alert(
title: Text("An …
Run Code Online (Sandbox Code Playgroud) 我了解如何使用 @EnvironmentObject 使全局数据可用于任何视图类,但我找不到将变量传递给非视图类的方法。
我的情况似乎是一个常见问题,是:
let contentView = ContentView()
.environmentObject(UserSettings())
Run Code Online (Sandbox Code Playgroud)
struct HomeView: View {
@EnvironmentObject var user: UserSettings <=== ACCESS TO GLOBAL DATA
@ObservedObject var categories = Categories() <=== GET DATA FOR THIS VIEW
var body: some View {
...
}
Run Code Online (Sandbox Code Playgroud)
class Categories : ObservableObject {
@Published var allCategories = CategoriesModel()
@EnvironmentObject var user: UserSettings <==== CANNOT ACCESS THIS DATA!
init() { …
Run Code Online (Sandbox Code Playgroud) 在我的 Swift 项目中使用时,我无法获得更新的预览@EnvironmentObject
。在模拟器中它工作正常,但预览却不行。它显示的错误如下:
ASET - Audio System Engineer Tools crashed due to missing environment of type: UserSettings. To resolve this add `.environmentObject(UserSettings(...))` to the appropriate preview.
Run Code Online (Sandbox Code Playgroud)
然而,当我尝试添加它时,它仍然出现同样的问题。有人有一些有用的建议或解决方案吗?
在编写我的第一个 iOS 应用程序的过程中,我遇到了一个新问题,到目前为止我无法找到解决方案:我想使用环境对象将信息传递到各种视图。
我知道对此有很多解释和教程(例如,在 hackingwithswift.com 上:https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data- Between-意见
然而,所有这些教程似乎都在使用“场景委托”,根据我目前的理解,Xcode 12 中不存在这种委托。
因此,我正在努力解决如何/在哪里放置环境对象在我的应用程序环境中以及如何将其连接到我的内容视图/其他视图。
这段代码应该放在哪里?它会进入内容视图吗?
class UserSettings: ObservableObject {
@Published var score = 0
}
Run Code Online (Sandbox Code Playgroud)
有人能帮忙解决这个问题吗?我会很感激 :)
我有一堂课:
class AppInfos_M: ObservableObject {
@Published var currentUser: User_M = User_M()
@Published var userTo: User_M = User_M()
}
Run Code Online (Sandbox Code Playgroud)
我声明它main
并传递到我的视图environmentObject
:
...
@main
struct TestApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
...
@StateObject var appInfos_M = AppInfos_M()
var body: some Scene {
WindowGroup {
LaunchScreen_V()
.environmentObject(appInfos_M)
...
}
}
}
Run Code Online (Sandbox Code Playgroud)
该课程在我的应用程序中运行得非常好。现在我需要从 修改它AppDelegate
,因为我需要appInfos_M.userTo.id
在收到通知时获取。我尝试了几件事,但没有一个有效。我怎样才能访问它?
在我需要它的所有视图中,我声明这种方式并且它工作正常,但不是在AppDelegate
,为什么?:
@EnvironmentObject var appInfos_M: AppInfos_M
Run Code Online (Sandbox Code Playgroud)
这是我尝试过但不起作用的测试之一:
...
class AppDelegate: NSObject, UIApplicationDelegate { ... }
...
@available(iOS 10, *)
extension AppDelegate : …
Run Code Online (Sandbox Code Playgroud) 我有一个网络监视器,我想在状态发生变化时接收通知。
看起来像这样:
final class NetworkMonitor: ObservableObject {
let monitor = NWPathMonitor()
let queue = DispatchQueue(label: "Monitor")
static let shared = NetworkMonitor()
@Published var status: NetworkStatus = .connected
func start() {
self.monitor.pathUpdateHandler = { [weak self] path in
guard let self = self else { return }
DispatchQueue.main.async {
self.status = (path.status == .satisfied) ? .connected : .disconnected
}
}
self.monitor.start(queue: self.queue)
}
}
Run Code Online (Sandbox Code Playgroud)
我在 Home 中创建一个网络监视器的@StateObject并通过环境对象发送它。
struct HomeView: View {
@StateObject var networkMonitor = NetworkMonitor()
var body: some …
Run Code Online (Sandbox Code Playgroud)