是否可以迁移旧的 Xcode 项目以使用 SwiftUI?

Is it possible to migrate an old Xcode project to use SwiftUI?

我有一个使用 Main.storyboard 在 Xcode 10 中制作的应用程序,我想将其迁移以使用 Apple 的新框架:SwiftUI。
已经可以了吗?

我已经尝试在 Info.plist 中添加 UIApplicationSceneManifest 键,我将 AppDelegate.swift 更改为使用场景,我创建了 SceneDelegate.swift 即使这样我也可以不是

我假设您使用的是 Xcode 11 GM 和 macOS MojaveCatalina

随着 plist 中的更改,您必须在应用程序委托中添加 UISceneSession 生命周期函数。

func application(_ application: UIApplication,
                 configurationForConnecting connectingSceneSession: UISceneSession,
                 options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    // The name must match the one in the Info.plist
    return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {

}

此外,您需要确保 windowSceneDelegate 中正确创建。

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

    guard let windowScene = scene as? UIWindowScene else {
        return
    }

    let window = UIWindow(windowScene: windowScene)
    window.rootViewController = UIHostingController(rootView: ContentView())
    self.window = window
    window.makeKeyAndVisible()
}

其中 ContentView 是您要显示的主要 SwiftUI 视图。

P.S。确保 plist 指定 $(PRODUCT_MODULE_NAME).SceneDelegate 作为委托 class 名称,场景委托称为 SceneDelegate

示例:

如果您使用 Catalina,您可以在目标的构建设置中打开 Previews

构建选项 -> 启用预览


附录 I:

确保从 Info.Plist 和 you're targeting iOS 13.

中删除 Storyboard


附录二:

清洁 Derived Data,正如评论中的许多开发者所建议的那样。

我的解决方案原来是不同的。在我的例子中,我已经准备好了一切,但是当代码试图加载 UISceneConfiguration 时,它无法加载 Info.plist 中的配置,而是给了我一个辅助 window 配置没有设置场景委托。如果我从调试控制台请求正确的配置,它将按预期加载。我一头雾水。

我仔细检查了所有内容并尝试了此处的所有建议,但 none 奏效了。最后我在模拟器上做了 'Hardware' - 'Erase all contents and settings...' 并解决了它。

我的猜测是,因为我在模拟器上使用的是 运行 应用程序的 pre-SwiftUI 版本,所以其中的某些内容导致 SwiftUI 版本的行为有所不同。

这是一个正确的小改动

SceneDelegate.swift中替换

let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = UIHostingController(rootView: ContentView())
self.window = window
window.makeKeyAndVisible()

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

取自