无法在此文件中预览 - [App Name].app 可能已在 Xcode 11 Beta 5 上崩溃

Cannot preview in this file - [App Name].app may have crashed on Xcode 11 Beta 5

如果我添加 EnviromentObject 属性 包装器,Xcode 预览将不起作用。每次我添加一个 Canvas 都不会构建,我会收到此错误:

Cannot preview in this file - [App Name].app may have crashed

如果我用 ObservedObject 替换 EnviromentObject 属性 包装器并初始化它,一切正常。

这是我的代码:

class NetworkManager: ObservableObject {

}

struct ContentView : View {
    @EnvironmentObject var networkManager: NetworkManager

    var body: some View {
        Text("Canvas not working")
    }
}

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

更新:

当我使用绑定时它也不会加载预览:

struct ContentView : View {
    @EnvironmentObject var networkManager: NetworkManager
    @Binding var test123: String

    var body: some View {
        Text("Canvas not working")
    }
}

#if DEBUG
struct ContentView_Previews: PreviewProvider {
    @State static var test1 = ""
    static var previews: some View {
        ContentView(test123: $test1).environmentObject(NetworkManager())
    }
}
#endif

看起来像 Xcode 问题。尝试使用蓝色按钮而不是 "Try Again"。

根据您提供的代码,我假设您的 SceneDelegate 看起来像这样:

if let windowScene = scene as? UIWindowScene {
    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = UIHostingController(rootView: ContentView())
    self.window = window
    window.makeKeyAndVisible()
}

我不会假装我确切地知道 canvas 在生成预览时在幕后做了什么,但基于错误明确指出应用程序可能已崩溃的事实,我假设它在尝试生成预览时试图启动整个应用程序。也许它需要使用 SceneDelegate 来启动预览,也许它完全是另外一回事 - 我不能肯定地说。

无论如何,应用程序崩溃的原因是您没有在 SceneDelegate 中传递环境对象。您的 SceneDelegate 应如下所示:

if let windowScene = scene as? UIWindowScene {
    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(NetworkManager()))
    self.window = window
    window.makeKeyAndVisible()
}

正如@graycampbell 所建议的,您需要确保将 EnvironmentObject 提供给 SceneDelegate 中的 ContentView。虽然很多预览/canvas 机制都在黑盒中,但 Xcode 的 UI 会建议调用新预览或刷新现有预览、构建(或更新相关部分) of) 应用程序的变体,即使是常规预览,也与 "Live Preview" 相对。如果 SceneDelegate 设置不正确,此过程可能会失败。

对于您的@Binding 问题,Binding.constant(_:) 应该有所帮助。根据 SwiftUI Documentation .constant 执行以下操作:

Creates a binding with an immutable value.

这是你想要的预览,而不是你的示例代码显示的@State。您可以在 this Apple tutorial.

的第 3 节中看到使用 .constant 的示例

所以不是这个:

#if DEBUG
struct ContentView_Previews: PreviewProvider {
    @State static var test1 = "Some Preview String"
    static var previews: some View {
        ContentView(test123: $test1)
             .environmentObject(NetworkManager())
    }
}
#endif

您可以执行以下操作:

#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(test123: .constant("Some Preview String"))
            .environmentObject(NetworkManager())
    }
}
#endif

通过此更改,您的代码预览非常适合我。 请记住,您再次需要在 SceneDelegate 或您使用此特定 ContentView 的任何其他地方为此绑定提供一个值。否则,您将 运行 陷入类似于您遇到 EnvironmentObject 的问题,只是幸运的是这一特定遗漏被编译器错误突出显示。

我确实有一个 解决方法,但是是的,错误确实存在于 XCode.
解决这个问题。您必须先设置 SceneDelegate

if let windowScene = scene as? UIWindowScene {
    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(NetworkManager()))
    self.window = window
    window.makeKeyAndVisible()
}. 

您还必须设置预览。看来你已经做到了。

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environmentObject(NetworkManager())
    }
}. 

最后,只需在您的 ContentView 中声明一个 @State 变量,与您 @Published@EnvironmentObject 的类型相同,无论您是否将其用于绑定ContentView 中的任何地方都没有关系。

@State var bindingVar: Double = 0.0

正如我之前所说,这是 XCode 错误,我不知道为什么 ContentView 需要一个相同类型的 @State 变量来开始预览 @EnvironmentObject 绑定代码。
可能是 ContentView_Previews 无法从 @EnvironmentObject 中找到绑定。

您可以在我的代码中看到下面的内容,它非常有效。

我遇到了同样的问题,我找到了原因。 我只是忘了添加 .environmentObject() 修饰符 到 ContentView() 在预览部分。

struct Content_Previews: PreviewProvider {
    static var previews: some View {
       ContentView().environmentObject(NetworkManager())
    }
}

这就是 Xcode 构建它的原因,没有显示代码错误, 但在 canvas 中预览时崩溃了。 - 简单的错误,我知道。