swift 在Xcode 12中使用@main

ssgvzors  于 2023-04-10  发布在  Swift
关注(0)|答案(6)|浏览(227)

我想在iOS 13及以上版本上运行此代码,我应该如何修复此错误?我想让此代码也可以在iOS 13上运行。

@available(iOS 14.0, *)
@main

struct WeatherProApp: App {
  @Environment(\.scenePhase) private var scenePhase
  @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

  
  var body: some Scene {
    WindowGroup{
      let fetcher = WeatherFetcher()
      let viewModel = WeeklyWeatherViewModel(weatherFethcer: fetcher)
      WeeklyWeatherView(viewModel: viewModel)
    }
    .onChange(of: scenePhase) { (newScenePhase) in
      switch newScenePhase {
      case .active:
        print("scene is now active!")
      case .inactive:
        print("scene is now inactive!")
      case .background:
        print("scene is now in the background!")
      @unknown default:
        print("Apple must have added something new!")
      }
    }
  }
}

但它显示了这个错误

kxxlusnw

kxxlusnw1#

以下是我如何在iOS 13上运行我的项目:
1.创建SceneDelegate(如果没有)

SceneDelegate.swift

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

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

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

1.打开info.plist作为源代码,并添加以下行:

信息列表

<key>UIApplicationSceneManifest</key>
       <dict>
           <key>UIApplicationSupportsMultipleScenes</key>
           <false/>
           <key>UISceneConfigurations</key>
           <dict>
           <key>UIWindowSceneSessionRoleApplication</key>
           <array>
               <dict>
                   <key>UISceneConfigurationName</key>
                   <string>Default Configuration</string>
                   <key>UISceneDelegateClassName</key>
                   <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
               </dict>
           </array>
       </dict>
   </dict>

1.将此添加到您的WeatherProApp.swift

WeatherProApp.swift

@main
    struct WeatherProAppWrapper {
        static func main() {
            if #available(iOS 14.0, *) {
                WeatherProApp.main()
            }
            else {
                UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(SceneDelegate.self))
            }
        }
    }
bnlyeluc

bnlyeluc2#

实际上,你可以在iOS 14之前的版本中使用@main属性,但你需要一个替代的AppDelegateSceneDelegate(你可以从iOS 13 Xcode项目中复制这两个委托类),你必须做一些额外的 Package 。
首先,你必须以下面的方式将@main属性应用于一个带有main函数的结构体,该函数根据iOS版本决定是使用WeatherProApp结构体还是AppDelegate类来启动:

@main
struct WeatherProAppWrapper {
    static func main() {
        if #available(iOS 14.0, *) {
            WeatherProApp.main()
        }
        else {
            UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(AppDelegate.self))
        }
    }
}

之后,您可以使用您的问题中显示的实现,只需删除@main属性,仅使用@available(iOS 14.0, *)。例如:

@available(iOS 14.0, *)
struct WeatherProApp: App {
    var body: some Scene {
        WindowGroup{
            ContentView()
        }
    }
}

我不知道你对UIKit有多熟悉,但你必须在SceneDelegate类中做同样的设置。

b91juud3

b91juud33#

这可能取决于其他项目代码,但下面的测试工作正常(Xcode 12b),所以可能会有帮助。
这个想法是将一个 Package 器隐藏在另一个带有可用性检查器的结构中:

@available(iOS 14.0, macOS 10.16, *)
struct Testing_SwiftUI2AppHolder {
    @main
    struct Testing_SwiftUI2App: App {

        var body: some Scene {
            WindowGroup {
                ContentView()
            }
        }
    }
}
iszxjhcz

iszxjhcz4#

如果你真的需要它,只需将@main更改为@UIApplicationMain,它应该会起作用。

cidc1ykv

cidc1ykv5#

结合@the.blaggy和@Ugo Marinelli的答案,我通过修改我的AppDelegate使其工作,而无需创建新的SceneDelegate:

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(
        _: UIApplication,
        didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        let window = UIWindow(frame: UIScreen.main.bounds)

        window.rootViewController = UIHostingController(
            rootView: ContentView()
        )
        self.window = window
        window.makeKeyAndVisible()
        return true
    }
}

我还像@the.blaggy一样 Package 了我的主结构体。

gk7wooem

gk7wooem6#

来自@the.blaggy的答案真的很有帮助,非常感谢主要想法。我只是没有AppDelegateSceneDelegate从iOS 13 Xcode项目复制这两个委托类。我只需要使用相同的新SwiftUI视图来支持iOS 13+和macOS,而不是创建旧的UIKit和AppKit视图。
AppDelegate允许我们在Swift中直接使用configurationForConnecting,而不是使用plist文件。
@UIApplicationDelegateAdaptor允许我们在iOS 14+上使用相同的AppDelegate
我在一个文件中写了MainAppWrapperMainAppAppDelegateSceneDelegate
该文件可以用作任何SwiftUI项目的启动模板,以便在任何操作系统下运行相同的SwiftUI的ContentView():iOS13、iOS14+、macOS。
只需将整个@main struct替换到此代码中,您将在所有操作系统下看到相同的ContentView()

import SwiftUI

@main
struct MainAppWrapper {
    static func main() {
        if #available(iOS 14.0, *) {
            MainApp.main()
        }
        else {
            #if os(iOS)
            UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil,
                NSStringFromClass(AppDelegate.self))
            #endif
        }
    }
}

@available(iOS 14.0, *)
struct MainApp: App {
    #if os(iOS)
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    #endif

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

#if os(iOS)
class AppDelegate: NSObject, UIApplicationDelegate, ObservableObject {
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        let config = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
        config.delegateClass = SceneDelegate.self
        return config
    }
}

class SceneDelegate: NSObject, UIWindowSceneDelegate, ObservableObject {
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        if #unavailable(iOS 14.0) {
          let contentView = ContentView()

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

相关问题