Swift SCENEDLEGATE xcode11的UIApplication.shared.delegate等效项?
我已在SceneDelegate中定义了一个let属性。我希望一些ViewController能够在场景中访问它 在UIKit中,我可以访问应用程序代理属性,如下所示:Swift SCENEDLEGATE xcode11的UIApplication.shared.delegate等效项?,swift,uiscenedelegate,Swift,Uiscenedelegate,我已在SceneDelegate中定义了一个let属性。我希望一些ViewController能够在场景中访问它 在UIKit中,我可以访问应用程序代理属性,如下所示: UIApplication.shared.delegate 然后强制转换并指定属性名称 是否存在从UIViewController实例获取对视图控制器所在的SceneDelegate的引用的等效项?从iOS 13开始,UIApplication具有connectedScenes属性,该属性设置为Set。每个场景都有一个委托,它
UIApplication.shared.delegate
然后强制转换并指定属性名称
是否存在从UIViewController实例获取对视图控制器所在的SceneDelegate的引用的等效项?从iOS 13开始,
UIApplication
具有connectedScenes
属性,该属性设置为Set
。每个场景都有一个委托
,它是一个UISceneDelegate
。因此,您可以通过这种方式访问所有的代理
场景可以管理一个或多个窗口(UIWindow
),您可以从其windowScene
属性获取窗口的UIScene
如果需要特定视图控制器的场景代理,请注意以下事项。从UIViewController
可以从其视图中获取其窗口。从窗口可以获得其场景,当然,从场景可以获得其代理
简而言之,从视图控制器,您可以执行以下操作:
let mySceneDelegate = self.view.window.windowScene.delegate
但是,很多时候视图控制器没有窗口。当视图控制器显示另一个全屏视图控制器时,会发生这种情况。当视图控制器位于导航控制器中且视图控制器不是顶部可见视图控制器时,可能会发生这种情况
这需要使用不同的方法来查找视图控制器的场景。最终,您需要结合使用漫游响应器链和视图控制器层次,直到找到通向场景的路径
以下扩展将(可能)从视图或视图控制器获取UIScene。获得场景后,可以访问其代理
添加UIResponder+Scene.swift:
导入UIKit
@可用(iOS 13.0,*)
扩展UIResponder{
@objc var场景:UIScene{
归零
}
}
@可用(iOS 13.0,*)
新世伸展{
@objc覆盖变量场景:UIScene{
回归自我
}
}
@可用(iOS 13.0,*)
扩展UIView{
@objc覆盖变量场景:UIScene{
如果let window=self.window{
返回窗口.windowScene
}否则{
返回自我。下一个?场景
}
}
}
@可用(iOS 13.0,*)
扩展UIViewController{
@objc覆盖变量场景:UIScene{
//试着走应答器链
var res=self.next?.scene
如果(res==nil){
//这不起作用。请尝试询问我的父视图控制器
res=自我。父母?场景
}
如果(res==nil){
//这不起作用。请尝试询问我的演示视图控制器
res=self.presentingViewController?场景
}
返回res
}
}
这可以从任何视图或视图控制器调用以获取其场景。但请注意,只有在至少调用了一次viewdide
之后,才能从视图控制器获取场景。如果您尽快尝试,则视图控制器可能尚未成为视图控制器层次结构的一部分
即使视图控制器视图的窗口为零,只要视图控制器是视图控制器层次结构的一部分,并且在该层次结构上的某个位置,它附加到一个窗口,这也将起作用
以下是UIResponder扩展的Objective-C实现: 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
我能够通过以下方式使其工作:
let scene = UIApplication.shared.connectedScenes.first
if let sd : SceneDelegate = (scene?.delegate as? SceneDelegate) {
sd.blah()
}
乔加林德
非常感谢。
我也以类似的方式解决了这个问题
// 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 */
}
我正在我的
MasterViewController中使用此选项:
- (void)viewDidLoad {
[super viewDidLoad];
SceneDelegate *sceneDelegate = (SceneDelegate *)self.parentViewController.view.window.windowScene.delegate;
}
self.view.window
此时为零,因此我必须找到其视图已加载并添加到窗口中的父视图
如果使用的是“分割视图控制器”,而场景代理是“分割代理”,则可以完全避免窗口/场景,只需执行以下操作:
SceneDelegate*SceneDelegate=(SceneDelegate*)self.splitViewController.delegate代码>
我在我的DetailViewController
中使用了此选项,如果您只想查找窗口,则无需引用SceneDelegate
:
(UIApplication.shared.connectedScenes.first as? UIWindowScene)?.windows.first
只有当你的应用程序只有一个场景和一个窗口时,你才应该使用这种方法。我将SceneDelegate的引用存储在静态弱
属性中,并在场景中初始化它(:willConnectTo:options)
class SceneDelegate:UIResponder,UIWindowSceneDelegate{
静态弱var共享:SceneDelegate?
func场景(场景:UIScene,willConnectTo会话:UISceneSession,选项connectionOptions:UIScene.connectionOptions){
Self.shared=Self
}
}
以后的场景可以使用SceneDelegate.shared
访问。self.view.window的值为零。。。如何访问当前场景的当前窗口?就像“老”appDelegate。window@Fabiosoft我更新了这个答案,让你在更多的条件下获得视图控制器的场景,即使窗口为零@正确的回答!我有在场景委托中处理OAuth回调的逻辑,以及我希望在回调发生时在ViewController中访问的闭包。此代码完全允许我访问ViewController中的场景代理以访问该闭包+1仅当您的应用程序有一个场景时,此选项才有效。支持场景的全部好处是可以有多个场景。当存在多个场景时,这样的代码将无法正常工作。这对于Azure的MSAL SDK集成非常有效。为此,我们节省了一些时间编码,以使MSAL身份验证模式可见。在UIApplication apple文档中完全查看了此属性。这是错误的,您得到的是任何第一次连接的UIScene
,而不是UIScene
(UIApplication.shared.connectedScenes.first as? UIWindowScene)?.windows.first