首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与@ObjectBinding和@EnvironmentObject绑定

与@ObjectBinding和@EnvironmentObject绑定
EN

Stack Overflow用户
提问于 2019-07-26 21:43:39
回答 2查看 2K关注 0票数 0

28-07-2019年。关于下面的代码,我仍然有一个问题。我想将数据模型从ContentView中分离出来。因此,我创建了一个单独的文件并添加了这个类,如下所示:

代码语言:javascript
复制
import SwiftUI
import Combine

class User: BindableObject {
    let willChange = PassthroughSubject<Void, Never>()
    var username : String = "Jan" { willSet { willChange.send() }}
    var password : String = "123456" { willSet { willChange.send() } }
    var emailAddress : String = "jan@mail.nl" { willSet { willChange.send() } }
}

#if DEBUG
struct User_Previews: PreviewProvider {
    static var previews: some View {
        User()
            .environmentObject(User())
    }
}
#endif

但是,这不起作用,我得到了一个错误:

代码语言:javascript
复制
Protocol type 'Any' cannot conform to 'View' because only concrete types can conform to protocols

错误发生在# if调试中的.environmentObject(User())行上。

在观看了一些视频之后,我编写了以下代码(包括对Xcode 11 beta 4的修改)。代码中已经包含了来自dfd和MScottWaller的两个答案的提示。

代码语言:javascript
复制
import Combine
import SwiftUI

class User: BindableObject {
    let willChange = PassthroughSubject<Void, Never>()
    var username = "Jan" { willSet { willChange.send() } }
    var password = "123456" { willSet { willChange.send() } }
    var emailAddress = "jan@mail.nl" { willSet { willChange.send() } }
}

struct ContentView: View {
    @EnvironmentObject var user: User

    private func buttonPressed() {
        print(user.username) // in Simulator
    }

    var body: some View {
        VStack {
            TextField("Username", text: $user.username)
            TextField("Password", text: $user.password)
            TextField("Emailaddress", text: $user.emailAddress)
            Button(action: buttonPressed) {
                Text("Press me!")
            }

        }
    }
}

#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(User())
    }
}
#endif

但现在进入下一部分。如果我有另一种看法..。那么,我如何引用这些数据呢?因为真相的来源在上面的ViewContent()视图中。答案是:

代码语言:javascript
复制
import SwiftUI

struct DetailView: View {
    @EnvironmentObject var user: User

    var body: some View {
        VStack {
            TextField("Username", text: $user.username)
            TextField("Password", text: $user.password)
            TextField("Email", text: $user.emailAddress)
        }
    }
}

#if DEBUG
struct DetailView_Previews: PreviewProvider {
    static var previews: some View {
        DetailView()
            .environmentObject(User())
    }
}
#endif

不要忘记编辑SceneDelegate (来自dfd的回答):

代码语言:javascript
复制
var user = User()

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(user)
        )
        self.window = window
        window.makeKeyAndVisible()
    }
} 
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-07-26 22:02:09

如果“真相的来源”是User,并且您已经将它变成了一个BindableObject,那么您只需要公开它,以便使它对您想要的各种视图都可用。我建议@EnvironmentObject

在您的SceneDelegate中,执行以下操作:

代码语言:javascript
复制
var user = User()

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(user)
        )
        self.window = window
        window.makeKeyAndVisible()
    }
}

既然用户的“有状态”实例可以用于任意视图,那么只需添加:

代码语言:javascript
复制
@EnvironmentObject var user: User

任何/所有需要了解User的人。

BindableObject (大部分情况下)为您拒绝的内容保留内存。@ObjectBinding只是将视图绑定到内存的这一部分中(同样,大多数情况下)。是的,您可以在所有视图中对User执行此操作--但是既然您是在ContentView中实例化它呢?)!@EnvironmentObject使任何需要访问它的视图都可以使用它。

当然,您可以使用@ObjectBinding 而不是@EnvironmentObject,但是到目前为止,?我从没听说过有什么理由这么做。

票数 2
EN

Stack Overflow用户

发布于 2019-07-27 00:25:13

在您的DetailView预览中,不要附加environmentObject。看看我是如何在下面的PreviewProvider中添加它的。当您运行实际的应用程序时,您将希望在SceneDelegate中对您的SceneDelegate做同样的操作

代码语言:javascript
复制
import SwiftUI

struct DetailView: View {
    @EnvironmentObject var user: User

    var body: some View {
        HStack {
            TextField("Username", text: $user.username)
            Text("Hello world!")
        }
    }
}

#if DEBUG
struct DetailView_Previews: PreviewProvider {
    static var previews: some View {
        DetailView()
            .environmentObject(User())
    }
}
#endif
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57227315

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档