A partir d'iOS 13, UIApplication
a le connectedScenes
qui est Set<UIScene>
. Chacune de ces scènes a une delegate
qui est un UISceneDelegate
. Vous pouviez donc accéder à tous les délégués de cette façon.
Une scène peut gérer une ou plusieurs fenêtres ( UIWindow
) et vous pouvez obtenir l'adresse de la fenêtre UIScene
de son windowScene
propriété.
Si vous voulez le délégué de scène pour un contrôleur de vue spécifique, notez ce qui suit. À partir d'un UIViewController
vous pouvez obtenir sa fenêtre à partir de sa vue. À partir de la fenêtre, vous pouvez obtenir sa scène et, bien sûr, à partir de la scène, vous pouvez obtenir son délégué.
En bref, depuis un contrôleur de vue, vous pouvez faire :
let mySceneDelegate = self.view.window.windowScene.delegate
Cependant, il arrive souvent qu'un contrôleur de vue n'ait pas de fenêtre. Cela se produit lorsqu'un contrôleur d'affichage présente un autre contrôleur d'affichage en plein écran. Cela peut se produire lorsque le contrôleur de vue se trouve dans un contrôleur de navigation et que le contrôleur de vue n'est pas le contrôleur de vue supérieur, visible.
Cela nécessite une approche différente pour trouver la scène du contrôleur de vue. En fin de compte, vous devez utiliser une combinaison de la chaîne des répondeurs et de la hiérarchie du contrôleur de vue jusqu'à ce que vous trouviez un chemin qui mène à la scène.
L'extension suivante vous permettra (peut-être) d'obtenir une UIScene à partir d'une vue ou d'un contrôleur de vue. Une fois que vous avez la scène, vous pouvez accéder à son délégué.
Ajouter UIResponder+Scene.swift :
import UIKit
@available(iOS 13.0, *)
extension UIResponder {
@objc var scene: UIScene? {
return nil
}
}
@available(iOS 13.0, *)
extension UIScene {
@objc override var scene: UIScene? {
return self
}
}
@available(iOS 13.0, *)
extension UIView {
@objc override var scene: UIScene? {
if let window = self.window {
return window.windowScene
} else {
return self.next?.scene
}
}
}
@available(iOS 13.0, *)
extension UIViewController {
@objc override var scene: UIScene? {
// Try walking the responder chain
var res = self.next?.scene
if (res == nil) {
// That didn't work. Try asking my parent view controller
res = self.parent?.scene
}
if (res == nil) {
// That didn't work. Try asking my presenting view controller
res = self.presentingViewController?.scene
}
return res
}
}
Cette fonction peut être appelée depuis n'importe quelle vue ou contrôleur de vue pour obtenir sa scène. Mais notez que vous ne pouvez obtenir la scène à partir d'un contrôleur de vue qu'après que la fonction viewDidAppear
a été appelé au moins une fois. Si vous essayez plus tôt, il se peut que le contrôleur de vue ne fasse pas encore partie de la hiérarchie des contrôleurs de vue.
Cela fonctionnera même si la fenêtre de la vue du contrôleur de vue est nulle, tant que le contrôleur de vue fait partie d'une hiérarchie de contrôleurs de vue et que, quelque part dans cette hiérarchie, il est attaché à une fenêtre.
Voici une implémentation en Objective-C de l'extension UIResponder :
UIResponder+Scene.h :
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIResponder (Scene)
@property (nonatomic, readonly, nullable) UIScene *scene API_AVAILABLE(ios(13.0));
@end
NS_ASSUME_NONNULL_END
UIResponder+Scene.m :
#import "ViewController+Scene.h"
@implementation UIResponder (Scene)
- (UIScene *)scene {
return nil;
}
@end
@implementation UIScene (Scene)
- (UIScene *)scene {
return self;
}
@end
@implementation UIView (Scene)
- (UIScene *)scene {
if (self.window) {
return self.window.windowScene;
} else {
return self.nextResponder.scene;
}
}
@end
@implementation UIViewController (Scene)
- (UIScene *)scene {
UIScene *res = self.nextResponder.scene;
if (!res) {
res = self.parentViewController.scene;
}
if (!res) {
res = self.presentingViewController.scene;
}
return res;
}
@end