SwiftUI 应用在支持 iOS 13 时不 运行
SwiftUI app doesn't run when supporting iOS 13
应用程序在部署目标为 15.2 时运行良好,但后来我需要将部署目标更改为 iOS 13 以支持更多设备。在 iOS 14+ 上仍然可以正常工作,但是当它在模拟器上运行在 iOS 13 上时会崩溃并出现异常 Thread 1: signal SIGABRT
。控制台没有显示调试信息:
CoreSimulator 802.6 - Device: iPhone 11 (iOS 13.0) (6CCC2B89-002B-4E83-8175-C244984BFC46) - Runtime: iOS 13.0 (17A577) - DeviceType: iPhone 11
Message from debugger: Terminated due to signal 9
以下是 WeatherApp.swift 文件代码的相关部分以及错误的屏幕截图:
@main
struct WeatherAppWrapper {
static func main() {
if #available(iOS 14.0, *) {
WeatherApp.main()
}
else {
UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(SceneDelegate.self))
}
}
}
struct WeatherApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject var loginStatus = UserLoginStatus()
@available(iOS 14.0, *)
var body: some Scene {
WindowGroup {
NavigationView{
if Methods.UserAccount.getFromUserDefaults()["username"] != nil {
MainView(loggedIn: $loginStatus.loggedIn)
LoginView(username: "", password: "", loggedIn: $loginStatus.loggedIn)
} else {
LoginView(username: "", password: "", loggedIn: $loginStatus.loggedIn)
MainView(loggedIn: $loginStatus.loggedIn)
}
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//Some app-specific setup code
...
return true
}
}
}
class UserLoginStatus: ObservableObject {
@Published var loggedIn: Bool {
didSet {
print("The value of loggedIn changed from \(oldValue) to \(loggedIn)")
}
}
init () {
loggedIn = false
}
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
@StateObject var loginStatus = UserLoginStatus()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let mainView = MainView(loggedIn: $loginStatus.loggedIn)
let loginView = LoginView(username: "", password: "", loggedIn: $loginStatus.loggedIn)
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
if Methods.UserAccount.getFromUserDefaults()["username"] != nil {
window.rootViewController = UIHostingController(rootView: mainView)
} else {
window.rootViewController = UIHostingController(rootView: loginView)
}
self.window = window
window.makeKeyAndVisible()
}
}
}
另外,这里是Info.plist文件的截图,具体展开相关区域:
根据 Apple docs,StateObject
仅适用于 iOS 14+。
StateObject
可从 SwiftUI 2.0 (iOS 14) 获得,旨在在视图中工作,而不是在 class 中工作(如 SceneDelegate
)
对于提供的场景,一个可能的解决方案是在顶层(在委托或主视图中)仅将 logicState
用作 属性,但将其完全注入子视图(而不是仅仅绑定)并在内部进行观察。
所以它应该看起来像
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var loginStatus = UserLoginStatus() // << just hold here
// ...
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let mainView = MainView(loginStatus: loginStatus) // << here !!
和
struct MainView: View {
@ObservedObject var loginStatus: UserLoginStatus // << injected here
// ...
}
类似的可以在WeatherApp
中完成
应用程序在部署目标为 15.2 时运行良好,但后来我需要将部署目标更改为 iOS 13 以支持更多设备。在 iOS 14+ 上仍然可以正常工作,但是当它在模拟器上运行在 iOS 13 上时会崩溃并出现异常 Thread 1: signal SIGABRT
。控制台没有显示调试信息:
CoreSimulator 802.6 - Device: iPhone 11 (iOS 13.0) (6CCC2B89-002B-4E83-8175-C244984BFC46) - Runtime: iOS 13.0 (17A577) - DeviceType: iPhone 11
Message from debugger: Terminated due to signal 9
以下是 WeatherApp.swift 文件代码的相关部分以及错误的屏幕截图:
@main
struct WeatherAppWrapper {
static func main() {
if #available(iOS 14.0, *) {
WeatherApp.main()
}
else {
UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(SceneDelegate.self))
}
}
}
struct WeatherApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@StateObject var loginStatus = UserLoginStatus()
@available(iOS 14.0, *)
var body: some Scene {
WindowGroup {
NavigationView{
if Methods.UserAccount.getFromUserDefaults()["username"] != nil {
MainView(loggedIn: $loginStatus.loggedIn)
LoginView(username: "", password: "", loggedIn: $loginStatus.loggedIn)
} else {
LoginView(username: "", password: "", loggedIn: $loginStatus.loggedIn)
MainView(loggedIn: $loginStatus.loggedIn)
}
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//Some app-specific setup code
...
return true
}
}
}
class UserLoginStatus: ObservableObject {
@Published var loggedIn: Bool {
didSet {
print("The value of loggedIn changed from \(oldValue) to \(loggedIn)")
}
}
init () {
loggedIn = false
}
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
@StateObject var loginStatus = UserLoginStatus()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let mainView = MainView(loggedIn: $loginStatus.loggedIn)
let loginView = LoginView(username: "", password: "", loggedIn: $loginStatus.loggedIn)
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
if Methods.UserAccount.getFromUserDefaults()["username"] != nil {
window.rootViewController = UIHostingController(rootView: mainView)
} else {
window.rootViewController = UIHostingController(rootView: loginView)
}
self.window = window
window.makeKeyAndVisible()
}
}
}
另外,这里是Info.plist文件的截图,具体展开相关区域:
根据 Apple docs,StateObject
仅适用于 iOS 14+。
StateObject
可从 SwiftUI 2.0 (iOS 14) 获得,旨在在视图中工作,而不是在 class 中工作(如 SceneDelegate
)
对于提供的场景,一个可能的解决方案是在顶层(在委托或主视图中)仅将 logicState
用作 属性,但将其完全注入子视图(而不是仅仅绑定)并在内部进行观察。
所以它应该看起来像
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var loginStatus = UserLoginStatus() // << just hold here
// ...
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let mainView = MainView(loginStatus: loginStatus) // << here !!
和
struct MainView: View {
@ObservedObject var loginStatus: UserLoginStatus // << injected here
// ...
}
类似的可以在WeatherApp