0

更改状态会自动关闭视图的奇怪行为。

Xcode 13.2.1、MacOS 12.2.1、iPhone 13 模拟器 iOS 15.something。

我在根视图中生成一个对象并使用@environmentObject(...) 将其传递到环境中,通过根视图中的 NavigationView 导航,沿途更新事物(在这种情况下,对象是数据收集器跨多个屏幕的帐户注册信息)。我进入了几个屏幕,whammo,对...的任何更新

@EnvironmentObject private var signupInfo: SignupInfo 

...对象导致解雇。它并不一致(意味着哪个屏幕会这样做),但无论它发生在哪个屏幕上,100% 的时间都会发生。

我不认为我的数据收集器对象有什么过分花哨的东西,即使在一个简单的测试视图上,它仍然会发生(粘贴在下面)。

我可以通过不在环境中使用随行对象并将其收集到本地状态或视图模型中来使它不会发生,但我仍然必须在某个时候将它们全部收集到位。如果不使用全局对象或将其持久化,我真的不喜欢任何其他复杂的想法。这应该只是工作。**抓头**

数据收集器对象

import Foundation

enum AccountType: Int {
    case none
    case journalOnly
    case singleIncident
    case preventive
}

class SignupInfo : ObservableObject {
    // seeding sample data for less typing during dev & testing
    @Published var email: String = "bob@bobberson.com"
    @Published var password: String = "skatanna99!"
    @Published var password2: String = "skatanna99!"
    @Published var firstname: String = "bob"
    @Published var lastname: String = "bobberson"
    @Published var address1: String = "123 Some Town Road"
    @Published var address2: String = ""
    @Published var city: String = "Newark"
    @Published var region: String = "DE"
    @Published var postalCode: String = "19701"
    @Published var phone: String = ""
    @Published var ccnumber: String = ""
    @Published var ccname: String = ""
    @Published var accountType: AccountType = .journalOnly
}

(当然不是真实信息)

因数据更改而崩溃或取消的视图。我想知道这是否是一个线程的事情,所以我有和没有调度。行为没有改变。我认为这与 navigationLink 堆栈的深度有关。

import SwiftUI

struct SignupServicesView: View {
    
    //@StateObject private var viewModel:ViewModel = ViewModel()
    @EnvironmentObject private var signupInfo: SignupInfo
    //@EnvironmentObject private var opData: OpData
    
    var body: some View {
        Text("account type is set to \(signupInfo.accountType.rawValue)")
            .onTapGesture {
                signupInfo.accountType = .preventive
            }
            .onLongPressGesture {
                DispatchQueue.main.async {
                    signupInfo.accountType = .preventive
                }
            }
    }
    
}

根视图实际上很简单(在这个精简的测试中),如下所示:(示例)

根视图 -> 创建@State 对象 (signupInfo = SignupInfo()) -> NavigationView -> 使用 .environmentObject(signupInfo) 链接到下一个视图

在 NavigationView 出现之前,我还尝试在先前的视图中创建状态并将其发送到环境中。没有改变任何东西。

想法……?

^ ^ ^ ^ ^编辑/更新^ ^ ^ ^ ^

有趣的是,当我将东西移到 viewModel 中时,一切正常,正如预期的那样。没有惊喜。但我仍然想要一个通用的地方来删除数据,而无需创建 CoreData 或 UserDefaults 条目。

当我将底层数据收集器对象移动到全局上下文并将其附加到视图模型时,如果我通过视图模型跳跃属性(视图更新视图模型,视图模型更新全局对象),它就会起作用。

但是,如果我只是直接暴露底层数据连接器,它仍然会以这种疯狂怪异的方式关闭视图。

将全局对象挂在应用程序的主视图之外(仅用于测试) public static var signupInfo = SignupInfo()

然后在 viewModel... 导入 Foundation

extension SignupServicesView {
    class ViewModel : ObservableObject {
        // works great
        @Published var firstname = theApp.signupInfo.firstname
    }
}

和视图:导入 SwiftUI

struct SignupServicesView: View {
    
    @StateObject private var viewModel:ViewModel = ViewModel()
    
    var body: some View {
        Text("account type is set to \(viewModel.firstname)")
            .onTapGesture {
                viewModel.firstname = "joe"
            }
            .onLongPressGesture {
                DispatchQueue.main.async {
                    viewModel.firstname = "joe"
                }
            }
            .navigationBarHidden(true)
    }
}

这一切都很棒。

直接暴露数据是行不通的。viewModel:导入 Foundation

extension SignupServicesView {
    class ViewModel : ObservableObject {
        @Published var signupInfo = theApp.signupInfo
    }
}

视图:导入 SwiftUI

struct SignupServicesView: View {
    
    @StateObject private var viewModel:ViewModel = ViewModel()
    
    var body: some View {
        Text("account type is set to \(viewModel.signupInfo.firstname)")
            .onTapGesture {
                viewModel.signupInfo.firstname = "joe"
            }
            .onLongPressGesture {
                DispatchQueue.main.async {
                    viewModel.signupInfo.firstname = "joe"
                }
            }
            .navigationBarHidden(true)
    }
}

所以,无论他们如何意识到它,直接与我的 SetupInfo 对象交谈对我的(某些)视图来说都是一个问题,但如果我能弄清楚为什么,该死的。

4

1 回答 1

1

经典的方法是将数据模型作为 astruct并通过类视图模型发布。不确定这是否适用于您的情况(您从哪里获取数据?)但它看起来像这样:

enum AccountType: Int {
    case none
    case journalOnly
    case singleIncident
    case preventive
}

// Data model as struct, not class
struct SignupInfo {
     var email: String = "bob@bobberson.com"
     var password: String = "skatanna99!"
     var password2: String = "skatanna99!"
     var firstname: String = "bob"
     var lastname: String = "bobberson"
     var address1: String = "123 Some Town Road"
     var address2: String = ""
     var city: String = "Newark"
     var region: String = "DE"
     var postalCode: String = "19701"
     var phone: String = ""
     var ccnumber: String = ""
     var ccname: String = ""
     var accountType: AccountType = .journalOnly
}


// global view model to publish the data model
class ViewModel : ObservableObject {
    @Published var signupInfo = SignupInfo()
}


// views, this one is creating the viewmodel, after that you can pass it down by environmentObject
struct SignupServicesView: View {
    
    @StateObject private var viewModel : ViewModel = ViewModel()
    
    var body: some View {
        Text("account type is set to \(viewModel.signupInfo.firstname)")
            .onTapGesture {
                viewModel.signupInfo.firstname = "joe"
            }
            .onLongPressGesture {
                viewModel.signupInfo.firstname = "Tom"
            }
            .navigationBarHidden(true)
    }
}
于 2022-02-23T18:55:08.927 回答