28-07-2019年。关于下面的代码,我仍然有一个问题。我想将数据模型从ContentView中分离出来。因此,我创建了一个单独的文件并添加了这个类,如下所示:
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但是,这不起作用,我得到了一个错误:
Protocol type 'Any' cannot conform to 'View' because only concrete types can conform to protocols错误发生在# if调试中的.environmentObject(User())行上。
在观看了一些视频之后,我编写了以下代码(包括对Xcode 11 beta 4的修改)。代码中已经包含了来自dfd和MScottWaller的两个答案的提示。
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()视图中。答案是:
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的回答):
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()
}
} 发布于 2019-07-26 22:02:09
如果“真相的来源”是User,并且您已经将它变成了一个BindableObject,那么您只需要公开它,以便使它对您想要的各种视图都可用。我建议@EnvironmentObject。
在您的SceneDelegate中,执行以下操作:
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()
}
}既然用户的“有状态”实例可以用于任意视图,那么只需添加:
@EnvironmentObject var user: User任何/所有需要了解User的人。
BindableObject (大部分情况下)为您拒绝的内容保留内存。@ObjectBinding只是将视图绑定到内存的这一部分中(同样,大多数情况下)。是的,您可以在所有视图中对User执行此操作--但是既然您是在ContentView中实例化它呢?)!@EnvironmentObject使任何需要访问它的视图都可以使用它。
当然,您可以使用@ObjectBinding 而不是@EnvironmentObject的,但是到目前为止,?我从没听说过有什么理由这么做。
发布于 2019-07-27 00:25:13
在您的DetailView预览中,不要附加environmentObject。看看我是如何在下面的PreviewProvider中添加它的。当您运行实际的应用程序时,您将希望在SceneDelegate中对您的SceneDelegate做同样的操作
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())
}
}
#endifhttps://stackoverflow.com/questions/57227315
复制相似问题