I am using Xcode 11 and building an app for iOS 13. In a new project I created in Xcode some of the UIApplicationDelegate methods were missing so I added them back into the app delegate file. The new template for a "Single View App" project was missing the methods. The problem is that none of the delegate methods are getting called except -application:didFinishLaunchingWithOptions:
. Here is my app delegate:
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"application:didFinishLaunchingWithOptions:");
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(@"applicationDidEnterBackground:");
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
NSLog(@"applicationWillEnterForeground:");
}
#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
}
@end
iOS 13 has a new way of sending app lifecycle events. Instead of coming through the UIApplicationDelegate
they come through the UIWindowSceneDelegate
which is a UISceneDelegate
sub-protocol. UISceneDelegate
has the important delegate methods.
This change is to support multiple windows in iOS 13. There's more information in WWDC 2019 session 212 "Introducing Multiple Windows on iPad". The technical information starts at around 14:30 and is presented by a man with very sparkly high-tops. The shorter session 258 Architecting Your App for Multiple Windows also has a great introduction to what's changed.
Here's how it works: If you have an "Application Scene Manifest" in your Info.plist and your app delegate has a configurationForConnectingSceneSession
method, the UIApplication
won't send background and foreground lifecycle messages to your app delegate. That means the code in these methods won't run:
applicationDidBecomeActive
applicationWillResignActive
applicationDidEnterBackground
applicationWillEnterForeground
The app delegate will still receive the willFinishLaunchingWithOptions:
and didFinishLaunchingWithOptions:
method calls so any code in those methods will work as before.
If you want the old behaviour back you need to
application:configurationForConnectingSceneSession:options:
method (or the Swift application(_:configurationForConnecting:options:)
function)@property (strong, nonatomic) UIWindow *window;
)Alternatively, open the SceneDelegate file that Xcode made and use the new lifecycle methods in there:
- (void)sceneDidBecomeActive:(UIScene *)scene {
}
- (void)sceneWillResignActive:(UIScene *)scene {
}
... etc
It's possible to use the new UIScene
lifecycle stuff without adopting multiple window support by setting "Enable Multiple Windows" ("UIApplicationSupportsMultipleScenes") to "NO" in the Info.plist (this is the default for new projects). This way you can start adopting the new API in smaller steps.
You can see that the scene delegate method names are a close match for the app delegate ones. One confusing thing is that the app delegate methods aren't deprecated so you won't get a warning if you have both app delegate and scene delegate methods in place but only one will be called.
Other things that UISceneDelegate
takes over are user activities (continueUserActivity:
etc), state restoration (stateRestorationActivityForScene:
etc), status bar questions and opening URLs. (I'm not sure if these replace the app delegate methods). It also has analogous notifications for the lifecycle events (like UISceneWillDeactivateNotification
).
From the WWDC Session, some images for you:
The function equivalents for Swift:
The class responsibilities: