简体   繁体   English

在 Xcode 中简化 SwiftUI 预览

[英]Streamlining SwiftUI Previews in Xcode

There's a lot of code my app normally runs that I would like to skip in Previews.我的应用程序通常会运行很多我想在预览中跳过的代码。 Code that is time-consuming and has no visible effects (such as initializing audio devices).耗时且没有可见效果的代码(例如初始化音频设备)。 I'm trying to figure out how skip it for previews.我试图弄清楚如何跳过它进行预览。

There is an easy way to run code only in the production build of an app using the DEBUG macro.有一种简单的方法可以使用 DEBUG 宏仅在应用程序的生产版本中运行代码。 But I don't know of anything similar for non-Preview builds (because Previews presumably build the same code as non-Previews).但我不知道非预览版有什么类似的东西(因为预览版可能会构建与非预览版相同的代码)。

I thought that setting a variable, previewMode , within my ViewModel, would work.我认为在我的 ViewModel 中设置一个变量previewMode会起作用。 That way I could set it to true only within the PreviewProvider:这样我只能在 PreviewProvider 中将其设置为 true:

struct MainView_Previews: PreviewProvider {

    static var previews: some View {
        let vm = ViewModel(previewMode: true)
        return MainView(viewModel: vm)
    }
}

and when I created the ViewModel within the SceneDelegate, I could set previewMode to false :当我在 SceneDelegate 中创建 ViewModel 时,我可以将previewMode设置为false

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

    let vm = ViewModel(previewMode: false)
    let mainView = MainView(viewModel: vm)

    // Use a UIHostingController as window root view controller.
    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: mainView)
        self.window = window
        window.makeKeyAndVisible()
    }
}

so that I can enclose any code I don't want to run for previews in if !previewMode { ••• }这样我就可以在if !previewMode { ••• }中包含我不想运行的任何预览代码

Unfortunately the code is still running.不幸的是,代码仍在运行。 Evidently the scene() function is getting called whenever my preview updates.显然,每当我的预览更新时,都会调用scene() function。 :( :(

How can I specify code to not run for previews?如何指定不运行预览的代码?

thanks!谢谢!

Practically Live-Preview mode run-time does not differ much from Simulator Debug mode run-time.实际上,实时预览模式运行时与模拟器调试模式运行时没有太大区别。 And this, of course, as intended to give us quick (as possible) feedback of our code execution.当然,这是为了给我们快速(尽可能)反馈我们的代码执行情况。

Anyway here are some findings... that might be used as solution/workaround for some cases that detection of Preview is highly desirable.无论如何,这里有一些发现......对于某些非常需要检测预览的情况,它们可能用作解决方案/解决方法。

So created from scratch SwiftUI Xcode template project and in all functions of generated entities add print(#function) instruction.因此从头开始创建 SwiftUI Xcode 模板项目,并在生成的实体的所有功能中添加print(#function)指令。

ContentView.swift ContentView.swift

import SwiftUI

struct ContentView: View {
    init() {
        print(#function)
    }

    var body: some View {
        print(#function)
        return someView()
            .onAppear {
                print(#function)
            }
    }

    private func someView() -> some View {
        print(#function)
        return Text("Hello, World!")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        print(#function)
        return ContentView()
    }
}

Perform Debug Preview and see output:执行调试预览并查看 output:

application(_:didFinishLaunchingWithOptions:)
application(_:configurationForConnecting:options:)
scene(_:willConnectTo:options:)
init()
sceneWillEnterForeground(_:)
sceneDidBecomeActive(_:)
2020-06-12 16:08:14.460096+0300 TestPreview[70945:1547508] [Agent] Received remote injection
2020-06-12 16:08:14.460513+0300 TestPreview[70945:1547508] [Agent] Create remote injection Mach transport: 6000026c1500
2020-06-12 16:08:14.460945+0300 TestPreview[70945:1547482] [Agent] No global connection handler, using shared user agent
2020-06-12 16:08:14.461216+0300 TestPreview[70945:1547482] [Agent] Received connection, creating agent
2020-06-12 16:08:15.355019+0300 TestPreview[70945:1547482] [Agent] Received message: < DTXMessage 0x6000029c94a0 : i2.0e c0 object:(__NSDictionaryI*) {
    "updates" : <NSArray 0x7fff8062cc40 | 0 objects>
    "id" : [0]
    "scaleFactorHint" : [3]
    "providerName" : "11TestPreview20ContentView_PreviewsV"
    "products" : <NSArray 0x600000fcc650 | 1 objects>
} > {
    "serviceCommand" : "forwardMessage"
    "type" : "display"
}
__preview__previews
init()
__preview__body
__preview__someView()
__preview__body
__preview__body
__preview__someView()
__preview__body

As it is clear complete workflow of app launching has been performed at start AppDelegate > SceneDelegate > ContentView > Window and only after this the PreviewProvider part.很明显,应用程序启动的完整工作流程已在启动AppDelegate > SceneDelegate > ContentView > Window并且仅在此之后PreviewProvider部分执行。

And in this latter part we see something interesting - all functions of ContentView in Preview mode have __preview prefix (except init)!!在后面的部分我们看到了一些有趣的东西——预览模式下ContentView的所有函数都有__preview前缀(除了 init)!!

So, finally, here is possible workaround (DISCLAIMER!!! - on your own risk - only demo)所以,最后,这是可能的解决方法(免责声明!!!-风险自负-仅演示)

The following variant以下变体

struct ContentView: View {

    var body: some View {
        return someView()
            .onAppear {
                if #function.hasPrefix("__preview") {
                    print("Hello Preview!")
                } else {
                    print("Hello World!")
                }
            }
    }

    private func someView() -> some View {
        if #function.hasPrefix("__preview") {
            return Text("Hello Preview!")
        } else {
            return Text("Hello World!")
        }
    }
}

Gives this给这个

演示

The only working solution I've found is to use the ProcessInfo.processInfo.environment value for key XCODE_RUNNING_FOR_PREVIEWS .我发现的唯一可行的解决方案是将ProcessInfo.processInfo.environment值用于键XCODE_RUNNING_FOR_PREVIEWS It's set to "1" only when running in preview mode:仅在预览模式下运行时才设置为“1”:

let previewMode: Bool = ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"

See this post .看到这个帖子

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

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