Opt out of UISceneDelegate/SwiftUI on iOS
While you should embrace using scenes when your app is run under iOS 13 and later, you can fully opt out while you still support iOS 12 or earlier.
Completely remove the “Application Scene Manifest” entry from Info.plist.
If there is a scene delegate class, remove it.
If there are any scene related methods in your app delegate, remove those methods.
If missing, add the property
var window: UIWindow?
to your app delegate.
Your app should now only use the app delegate and under iOS 13 it should have the same life cycle as iOS 12.
Note: None of this is specific to Swift or SwiftUI.
SwiftUI app doesn't run when supporting iOS 13
The StateObject
is available from SwiftUI 2.0 (iOS 14) and is designed to work in View, not in class (like SceneDelegate
)
For provided scenario a possible solution is to use logicState
as just property at top level (in delegate or main view), but inject it completely into child views (instead of just binding) and observe it internally.
So it should look like
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 !!
and
struct MainView: View {
@ObservedObject var loginStatus: UserLoginStatus // << injected here
// ...
}
similar can be done in WeatherApp
How do you migrate to the new SwiftUI App Protocol?
You need to follow these steps to migrate a SwiftUI application to the new App
life cycle:
- Create a new
App
struct and add the@main
annotation:
@main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Remove the
@main
annotation fromAppDelegate
.Remove
Scene Configuration
fromInfo.plist
:
- (Optionally) Move
AppDelegate
/SceneDelegate
methods:
- SwiftUI app life cycle iOS14 where to put AppDelegate code?
- Is there any way to call SceneDelegate methods in iOS 14 app life cycle?
- Now you can remove the
AppDelegate
andSceneDelegate
classes from the project (first make sure the app is indeed working as expected).
How to use old method of setting rootViewController in AppDelegate using Swift
Follow these steps to use AppDelegate and opt-out for SceneDelegate
- Go to Info.plist and remove Application Scene Manifest entry from Info.plist.
- Remove SceneDelegate.swift
- Add
var window: UIWindow?
in your AppDelegate.swift file Delete the UISceneSession Lifecycle code from AppDelegate.swift
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window : UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let mainStoryBoard = UIStoryboard(name: "Main", bundle: Bundle.main)
let loginController = mainStoryBoard.instantiateViewController(withIdentifier: "HomeViewController")
self.window?.rootViewController = loginController
self.window?.makeKeyAndVisible()
return true
}
}
Make sure to give "HomeViewController" storyboardID to your view controller.
This is how your AppDelegate.swift file should look now. You are good to go!
Call external method from AppDelegate swiftui
@EnvironmentObject
is only for a SwiftUIView
it does not work in aclass
@EnvironmentObject
has to be injected in the parentView
theAppDelegate
has no way of knowing about it.One approach is to have the
AppDelegate
own theclient
and then make is available to the subviews of theapp1App
Remove from app1App
var client : Client = Client()
Then change the AppDelegate
class AppDelegate: NSObject, UIApplicationDelegate {
let client : Client = Client()
//the rest of the delegate
}
Then inject the client
to the subviews by replacing
MainView().environmentObject(client)
With
MainView().environmentObject(appDelegate.client)
The client
will be available by appDelegate.client
This of course assumes the the client
is an ObservableObject
SwiftUI, changing a view from scene(:continue
It would be appropriate to use EnvironmentObject
in this scenario
class AppState: ObservableObject
@Published var someVar: Sometype
}
class SceneDelegate {
let appState = AppState()
func scene(_ scene: UIScene,
continue userActivity: NSUserActivity) {
// ... other code
appState.someVar = ... // modify
}
}
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// .. other code
let contentView = ContentView()
.environmentObject(appState)
//
}
}
struct ContentView: View {
@EnvironmentObject var appState
var body: some View {
VStack {
// ... other code
appState.someVar // use here as needed
}
}
}
ios - Is LaunchScreen required in SwiftUI apps for the AppStore?
A launchscreen
is still needed for your application, so the Apple docs are correct.
For SwiftUI applications you can configure your launchscreen
through the info.plist provided for your application alternatively you could probably retrofit the storyboard back in.
For guidance on how to configure your launchscreen
through the plist file I'd suggest taking a look at this article.
Related Topics
How to Deal With @Objc Inference Deprecation With #Selector() in Swift 4
Swift - How to Convert String to Double
Deinit Method Is Never Called - Swift Playground
All Dates Between Two Date Objects (Swift)
How to Display an Activity Indicator With Text on iOS 8 With Swift
Getting Keyboard Size from Userinfo in Swift
Get Integer Value from String in Swift
Delete Folder With Contents from Firebase Storage
Swift 4 Decodable - Dictionary With Enum as Key
Extensions in My Own Custom Class
The Use of Swift 3 @Objc Inference in Swift 4 Mode Is Deprecated
What Does It Mean That String and Character Comparisons in Swift Are Not Locale-Sensitive
Get Class Name of Object as String in Swift
Swift 2 - Pattern Matching in "If"
Fatal Error: Swapping a Location With Itself Is Not Supported With Swift 2.0