Should my app be updated to Scene Delegate from App Delegate. My app supports ios 13.0 and up
first you have to understand what is difference
You could think of them as the global and private versions. One is shared and the other is limited to the individual owner. In a way, they are exactly what you would expect by the names.
Multi-window support is happening
Next time you create a new Xcode project you’ll see your AppDelegate has split in two: AppDelegate.swift and SceneDelegate.swift. This is a result of the new multi-window support that landed with iPadOS, and effectively splits the work of the app delegate in two.
From iOS 13 onwards, your app delegate should:
Set up any data that you need for the duration of the app.
Respond to any events that focus on the app, such as a file being shared with you.
Register for external services, such as push notifications.
Configure your initial scenes.
In contrast, scene delegates are there to handle one instance of your app’s user interface. So, if the user has created two windows showing your app, you have two scenes, both backed by the same app delegate.
Keep in mind that these scenes are designed to work independently from each other. So, your application no longer moves to the background, but instead individual scenes do – the user might move one to the background while keeping another open.
at last I will say that you can go with Scene Delegate
Courtesy of https://www.hackingwithswift.com/articles/193/whats-new-in-ios-13
Related
This question already has answers here:
Opt out of UISceneDelegate/SwiftUI on iOS
(6 answers)
Closed 3 months ago.
The question says it all.
There's the following line in apple documentation,
Scenes are opt in, but you must support them if you want to display
multiple copies of your app’s UI simultaneously.
It's not mentioned whether the SceneDelegate is mandatory or optional or a recommendation (I'm aware that the SceneDelgate is used to handle the lifecycle of the scene).
In a iOS 13+ device, can I create an app without SceneDelegate?
I defined the UIWindow variable in the AppDelgate and set the ViewController in application(didFinishLaunchingWithOptions), like before iOS 13. But that doesn't work and displays a blank screen.
And thus, this question. Is Scenedelgate mandatory even if we don't opt for multiple scenes?
Here's my observation:
Multiple scenes are optional. But you still have to support at least
one scene... and for that, SceneDelegate is mandatory.
If I'm wrong and SceneDelegate is optional (like described in this stackoverflow post), please help with the flows.
In a iOS 13+ device, can I create an app without SceneDelegate?
Yes. All apps do have scenes, but if you go with the app-delegate-only architecture, a single UIWindowScene will be created behind the scenes (pun intended). The app will run perfectly well on both iPhone and iPad, with all the usual lifetime events arriving as usual into the app delegate (though I do not know what will happen on Apple Silicon).
I defined the UIWindow variable in the AppDelgate and set the ViewController in application(didFinishLaunchingWithOptions), like before iOS 13. But that doesn't work and displays a blank screen.
This is because you did not correctly convert from the scene delegate architecture, which is provided by the app template you started with, to an app delegate architecture. Basically, you've left pieces of the scene delegate architecture lying around. Perhaps you did not delete all references to the scene delegate; perhaps you forgot to delete the UIApplicationSceneManifest entry from the Info.plist. Whatever the reason, the result is that the runtime thinks this app still uses scene delegate architecture, and it then fails to find certain pieces that it's looking for and shows the blank screen.
So, just to sum up what to do when you've started with the built-in app template:
Delete the SceneDelegate.swift file.
In the App Delegate, delete the two UISceneSession methods.
In the App Delegate, add a window reference as an instance property: var window: UIWindow?
In the Info.plist, completely delete the entire UIApplicationSceneManifest entry (and save).
Profit.
I can't find a clear definition of what UIScenes are
Are they just for handling the background calls? Are they like a ViewController? Do we use them often or nah?
The biggest thing is that scenes set up multiple window support. It is also useful for SwiftUI.
The SceneDelegate controls what is displayed on the screen "to manage life-cycle events in one instance of your app's user interface.", while the AppDelegate controls your entire app life-cycle.
Read the App and Environment Article and scenes from Apple instead of UIScene documentation.
Scene:
Scene, Manage multiple instances of your app’s UI simultaneously, and
direct resources to the appropriate instance of your UI.
We had only one scene back then before iOS 13, So the only thing we need to run ViewControllers simultaneously was multiple Windows on top of each other. But now, each application can have multiple instances running at the same time! Each scene has its own state and it might be in the foreground while others are in the background or are suspended, while Window was completely dependent on the application itself.
Imagine we have 2 view controllers (consider there are no scenes) running on the left and right side of the device and then we need to show a banner. Using the old window method will show the banner on both of them! And if you need to pick one, you may end up finding the correct controller and presenting the banner on it.
So apple introduced Scene, a container for each separate instance of the app. So you can manage each one separately and each of them acts as a separate app. It has its own windows and controllers. But all of them are managed by a single object, UIApplication.shared and it has a delegate to handle general events (usually from outside of the app) and entire application life cycle.
The apple developer docs mentions that multiple instances of a scene are available on iOS 13 (ie both iPhone and iPad)
From their developer docs:
In iOS 13 and later, the user can create and manage multiple instances of your app's user interface simultaneously, and switch between them using the app switcher. On iPad, the user can also display multiple instances of your app side by side. Each instance of your UI displays different content, or displays the same content in a different way. For example, the user can display one instance of the Calendar app showing a specific day, and another showing an entire month.
I have tried it on iPadOS and I am able to create multiple scene instances using the gesture and UI actions mentioned in their WWDC videos but I have not found any reference around how to achieve that on iPhone, it would be really helpful to know how to achieve this or whether it is possible or not.
The documentation you quote is misleading due to the use of the term "iOS".
The ability to create multiple scenes for an app in iOS 13 is actually limited to iPads and iPadOS. You can't create more than the one app scene on an iPhone in iOS.
Use UIApplication.sharedApplication.supportsMultipleScenes (Objective-C) / UIApplication.shared.supportsMultipleScenes (Swift) to check if the current device supports multiple scenes. You will find that this return NO/false on iPhones and YES/true on iPads.
That check is useful to enable/disable the ability to use drag and drop that creates an NSUserActivity or UI components that lead to uses of UIApplication requestSceneSessionActivation.
I have a simple "timer" watchOS app that uses hierarchical navigation. I can press the digital crown to return to the watch Springboard, then tap the app icon and be returned to the same interface controller I was using.
If I return to the watch face and tap my app's complication, the app is launched, but appears to have restarted: I lose my current state. Is there any way to prevent this?
It sounds like you're asking how to stop your app being swapped out of memory?
If so, just like on iOS this isn't possible - and obviously the watch has less memory than a phone so is more likely to be swapped out.
What you need to do is store your state in some persistence layer - e.g. NSUserDefaults - so when the app restarts it can reload its state
If you open your watch app by tap complication, the app will automatically back to root interface controller(s). This is a system forced behavior.
If you want to preserve previous state, you need to change your app's hierarchic to page-based interfaces.
User interaction in page-based interfaces can be just like navigation-based interfaces. You can replace pushController(withName:context:), pop() and popToRootController() methods to becomeCurrentPage(). I also found switch from one page interface to another is also faster than navigation (push/pop) to another.
In xcode you need to specify the initial interface controller for the watch app, which is the entry point of the watch app, shown first when you open it.
But is it shown every time you open the watch app? For example you open a watch app, navigate to a page, close it, and open it again. Does it open on the page you were last time (like on iOS), or again on the first interface controller?
According to apple documentation:
Normally, WatchKit displays the first interface controller in the sequence initially.
Well, normally is not every time. I looked through watch app videos from the watch presentation event, but there wasn't a case when they opened an app twice.
That's a great question!
Main Entry Point
First off, you can certainly avoid showing that MainInterfaceController each time. See this thread for more information where I detail exactly how to use that entry point to launch the appropriate set of InterfaceController objects.
Watch Extension Lifecycle
It is VERY important to understand what the expected lifecycle of a Watch Extension actually is. It will only run while the user has the Watch up and is running your app. This will generally be 1-5 seconds (opinionated value). As soon as the user lowers their wrist, your Watch Extension will be terminated completely. Therefore, it is going to be restarted every time at the same entry point. This means that you need to track your app state if you want to launch a different page set in the MainInterfaceController.
Hopefully that helps shed some light.
If your WatchKit extension is still running, it will pick up where you left off. If not, and everything has been dumped out of memory, it should start again with your initial interface controller.