简体   繁体   English

如何在 SwiftUI NavigationView 中重新初始化类

[英]How to re-initialise classes in a SwiftUI NavigationView

I have two views - a MasterView and DetailView.我有两个视图 - MasterView 和 DetailView。 When opening the DetailView, I initialise a new class that tracks data about the view (in the real implementation, the detail view involves a game).打开 DetailView 时,我初始化了一个新的 class 来跟踪有关视图的数据(在实际实现中,详细视图涉及游戏)。

However, when I press the back button from the DetailView to return to the MasterView, and then press the button to return to the DetailView, my class is unchanged.但是,当我从 DetailView 按下返回按钮返回到 MasterView,然后按下按钮返回到 DetailView 时,我的 class 没有改变。 However, I would like to re-initialise a new copy of this class (in my case to re-start the game) whenever I move from the MasterView to the DetailView.但是,每当我从 MasterView 移动到 DetailView 时,我想重新初始化这个 class 的新副本(在我的情况下是重新启动游戏)。

I have condensed the problem to this code:我已将问题浓缩为这段代码:

import SwiftUI
import Combine

class Model: ObservableObject {
    @Published var mytext: String = "mytext"
}

struct MasterView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: DetailView(model: Model())) {
                Text("press me")
            }
        }
    }
}

struct DetailView: View {
    @ObservedObject var model: Model = Model()

    var body: some View {
        TextField("Enter here", text: $model.mytext)
    }
}


struct MasterView_Previews: PreviewProvider {
    static var previews: some View {
        MasterView()
    }
}

I would like to create a new instance of Model every time I click the NavigationLink to the detail view, but it seems like it always refers back to the same original instance - I can see this by typing a change into the text field of the DetailView, which persists if I go back and forward again.每次单击 NavigationLink 到详细视图时,我都想创建一个Model的新实例,但它似乎总是指回相同的原始实例 - 我可以通过在 DetailView 的文本字段中输入更改来查看,如果我再次来回 go ,这种情况仍然存在。

Is there any way of doing this?有没有办法做到这一点?

Based on your comments - and correct me where wrong - here's how I'd set things up.根据您的评论 - 并纠正我的错误 - 这就是我的设置方式。

Your needs are:您的需求是:

  • A "base" class.一个“基础”class。 Call it MasterView , "settings", "view state", whatever. MasterView 、“设置”、“视图状态”等等。 This is where everything starts.这是一切开始的地方。
  • A "current game".... well, it could be a struct , a class , even properties in an ObservableObject . “当前游戏”....好吧,它可以是structclass ,甚至是ObservableObject中的属性。

I think that's about it.我想就是这样。 Hierarchically, your model could be:从层次上讲,您的 model可能是:

ViewState视图状态

...Player ...播放器

......Properties, including ID and history ......属性,包括 ID 和历史记录

...Current Game ...当前游戏

...... Properties, including difficulty ......属性,包括难度

Please note, I've changed some names and am being very vague on properties.请注意,我已经更改了一些名称,并且对属性非常模糊。 The point is, you can encapsulate all of this in an ObservableObject , create an `EnvironmentObject of it, and have all your SwiftUI views "react" to changes in it.关键是,您可以将所有这些封装在ObservableObject中,为其创建一个 `EnvironmentObject,并让所有 SwiftUI 视图对其中的更改“做出反应”。

Leaving out views, hopefully you can see where this "model" can contain just about all the Swift code you wish to do everything - now all you need is to tie in your views.省略视图,希望您可以看到这个“模型”可以包含几乎所有您希望做所有事情的 Swift 代码 - 现在您所需要的只是绑定您的视图。

(1) Create your ObservableObject . (1) 创建您的ObservableObject It needs to (a) be a class object and (b) conform to the ObservableObject protocol.需要(a) 是 class object 和 (b) 符合ObservableObject协议。 Here's a simple one:这是一个简单的:

class ViewState : ObservableObject {
    var objectWillChange = PassthroughSubject<Void, Never>()
    @Published var playerID = ""  {
        willSet {
            objectWillChange.send()
        }
    }
}

You can create more structs/classes and instantiate them as needed in your model.您可以根据需要在 model 中创建更多结构/类并实例化它们。

(2) Instantiate ViewState once min your environment. (2) 在您的环境中实例化一次ViewState In SceneDelegate :SceneDelegate

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: ContentView()
            .environmentObject(ViewState())
        )
        self.window = window
        window.makeKeyAndVisible()
    }
}

Note that there's a single line added here and that ViewState is instantiated a single time.请注意,这里添加了一行,并且ViewState被实例化了一次。

(3) Finally, in any SwiftUI view that needs to know your view state, bind it by adding one line of code: (3)最后,在任何需要知道你的视图state的SwiftUI视图中,通过添加一行代码进行绑定:

@EnvironmentObject var model: ViewState

If you want, you can do virtually anything in your model ( ViewState ) from instantiating a new game, flag something to result in a modal popup, add a player to an array, whatever.如果您愿意,您几乎可以在 model ( ViewState ) 中执行任何操作,包括实例化新游戏、标记某些内容以导致模式弹出窗口、将玩家添加到数组等等。

The main thing I hope I'm explaining is there's no need to instantiate a second view state - rather instantiate a second game instance inside your single view state.我希望我要解释的主要内容是无需实例化第二个视图 state - 而是在单个视图 state 中实例化第二个游戏实例

Again, if I'm way off from your needs, let me know - I'll gladly delete my answer.同样,如果我与您的需求相去甚远,请告诉我 - 我很乐意删除我的答案。 Good luck!祝你好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM