Difference Between Scenedelegate and Appdelegate

Difference between SceneDelegate and AppDelegate

The two files are meant to split the work by what is needed to run the app as a whole and what is needed for one "instance" that would support visibly running in the background. This would be something like configuring a database once, but displaying different sets of values by window.

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:

  1. Set up any data that you need for the duration of the app.
  2. Respond to any events that focus on the app, such as a file being shared with you.
  3. Register for external services, such as push notifications.
  4. 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.

Courtesy of https://www.hackingwithswift.com/articles/193/whats-new-in-ios-13

AppDelegate and SceneDelegate when supporting iOS 12 and 13

You do need to duplicate the code but you need to make sure it runs only on the correct system. In iOS 13 you don’t want that application delegate didFinishLaunching body code to run, so use an availability check to prevent it.
In the same way, use availability to hide the window scene stuff from iOS 12.

Here's the basic sketch of a solution that runs correctly on both iOS 12 and iOS 13:

AppDelegate.Swift

import UIKit
@UIApplicationMain
class AppDelegate : UIResponder, UIApplicationDelegate {
var window : UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey : Any]?)
-> Bool {
if #available(iOS 13, *) {
// do only pure app launch stuff, not interface stuff
} else {
self.window = UIWindow()
let vc = ViewController()
self.window!.rootViewController = vc
self.window!.makeKeyAndVisible()
self.window!.backgroundColor = .red
}
return true
}
}

SceneDelegate.swift

import UIKit
@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window : UIWindow?
func scene(_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
self.window = UIWindow(windowScene: windowScene)
let vc = ViewController()
self.window!.rootViewController = vc
self.window!.makeKeyAndVisible()
self.window!.backgroundColor = .red
}
}
}

ViewController.swift

import UIKit
class ViewController : UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("view did load")
self.view.backgroundColor = .green
}
}

Note that dealing with other duplicates, such as the application activating, is much simpler because if you support window scenes the application delegate method won't be called on iOS 12. So the problem is confined to this one situation, namely where you have window / root view controller manipulations to perform at launch (e.g. no storyboard).

How to share an object between AppDelegate and SceneDelegate

Just need
help with sharing the client between the two delegates - any
suggestions?

If it is app-wide to be shared then the simplest is to make it global

let client : Client = Client()    // << create here

class AppDelegate: NSObject, UIApplicationDelegate {
// access `client` here directly
// other Notifications related functions
}

class SceneDelegate: NSObject, UIWindowSceneDelegate {

func sceneWillEnterForeground(_ scene: UIScene) {
// access `client` here directly
client.disconnect() // This fails in runtime!!!
}
}

SceneDelegate function is never called

I have no idea why my SceneDelegate wasn't working, but I did two things:

  1. Deleted the app from the simulator I was using.
  2. Restarted Xcode.

My SceneDelegate now works as expected.

Set UIWindow in AppDelegate with SceneDelegate

In AppDelegate I removed the lines which contains functions of UISceneSession Lifecyle then it worked it.

// MARK: UISceneSession Lifecycle

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}

func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}

Than add var window: UIWindow? property to AppDelegate and inited it and set rootViewController programmatically, then worked it but for detail information, I will edit my answer as soon as I learned about UIScene workflow.

How to use @EnvironmentObject to share data between AppDelegate and SceneDelegate/Views in SwiftUI

Maybe you can use the UIApplication.shared.delegate to get the AppDelegate an access the user data:

class AppDelegate: UIResponder, UIApplicationDelegate {

var userData: UserData!

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
userData = UserData()
return true
}
}
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).

let userData = (UIApplication.shared.delegate as! AppDelegate).userData

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


Related Topics



Leave a reply



Submit