Después de tanto trabajar hemos encontrado el arreglo de este dilema que muchos lectores de nuestro sitio web presentan. Si tienes algún detalle que aportar no dudes en aportar tu comentario.
Solución:
A partir de iOS 13, UIApplication
tiene el connectedScenes
propiedad que es Set
. Cada una de esas escenas tiene un delegate
el cual es un UISceneDelegate
. Entonces podría acceder a todos los delegados de esa manera.
Una escena puede gestionar una o más ventanas (UIWindow
) y puede obtener una ventana UIScene
de su windowScene
propiedad.
Si desea el delegado de escena para un controlador de vista específico, tenga en cuenta lo siguiente. A partir de una UIViewController
puedes obtener su ventana desde su vista. Desde la ventana puede obtener su escena y, por supuesto, desde la escena puede obtener su delegado.
En resumen, desde un controlador de vista, puede hacer:
let mySceneDelegate = self.view.window.windowScene.delegate
Sin embargo, hay muchas ocasiones en las que un controlador de vista no tiene ventana. Esto sucede cuando un controlador de vista presenta otro controlador de vista de pantalla completa. Esto puede suceder cuando el controlador de vista está en un controlador de navegación y el controlador de vista no es el controlador de vista visible superior.
Esto requiere un enfoque diferente para encontrar la escena del controlador de vista. En última instancia, debe usar una combinación de caminar por la cadena de respuesta y la jerarquía del controlador de vista hasta que encuentre un camino que conduzca a la escena.
La siguiente extensión (puede) obtener una UIScene desde una vista o un controlador de vista. Una vez que tenga la escena, puede acceder a su delegado.
Agregue 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
Esto se puede llamar desde cualquier vista o controlador de vista para obtener su escena. Pero tenga en cuenta que solo puede obtener la escena desde un controlador de vista solo después de viewDidAppear
ha sido llamado al menos una vez. Si lo intenta antes, es posible que el controlador de vista aún no forme parte de la jerarquía del controlador de vista.
Esto funcionará incluso si la ventana de la vista del controlador de vista es nula, siempre que el controlador de vista sea parte de una jerarquía de controladores de vista y en algún lugar de esa jerarquía, esté adjunto a una ventana.
Aquí hay una implementación de Objective-C de la extensión UIResponder:
UIResponder+Escena.h:
#import
NS_ASSUME_NONNULL_BEGIN
@interface UIResponder (Scene)
@property (nonatomic, readonly, nullable) UIScene *scene API_AVAILABLE(ios(13.0));
@end
NS_ASSUME_NONNULL_END
UIResponder+Escena.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
Pude hacerlo funcionar usando esto:
let scene = UIApplication.shared.connectedScenes.first
if let sd : SceneDelegate = (scene?.delegate as? SceneDelegate)
sd.blah()
JoeGalind Gracias, también lo resolví de manera similar.
// iOS13 or later
if #available(iOS 13.0, *)
let sceneDelegate = UIApplication.shared.connectedScenes
.first!.delegate as! SceneDelegate
sceneDelegate.window!.rootViewController = /* ViewController Instance */
// iOS12 or earlier
else
// UIApplication.shared.keyWindow?.rootViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window!.rootViewController = /* ViewController Instance */
Al final de la post puedes encontrar las aclaraciones de otros desarrolladores, tú incluso puedes dejar el tuyo si dominas el tema.