我已经在SceneDelegate中定义了出租房产.我希望一些ViewController能够在场景中访问它.
在UIKit中,我可以访问如下应用程序代理属性:
UIApplication.shared.delegate
然后强制转换并指定属性名称...
从UIViewController的实例中获取对视图控制器所在的SceneDelegate的引用是否有一个类似功能?
我已经在SceneDelegate中定义了出租房产.我希望一些ViewController能够在场景中访问它.
在UIKit中,我可以访问如下应用程序代理属性:
UIApplication.shared.delegate
然后强制转换并指定属性名称...
从UIViewController的实例中获取对视图控制器所在的SceneDelegate的引用是否有一个类似功能?
截至iOS 13,UIApplication
具有connectedScenes
属性,即Set<UIScene>
.每个场景都有一个delegate
,也就是UISceneDelegate
.所以你可以通过这种方式访问所有代表.
一个场景可以管理一个或多个窗口(UIWindow
),您可以从其windowScene
属性中获取窗口的UIScene
.
如果需要特定视图控制器的场景代理,请注意以下事项.从UIViewController
中你可以看到它的窗口.从窗口可以看到它的场景,当然也可以从场景中看到它的代理.
简而言之,从视图控制器,可以执行以下操作:
let mySceneDelegate = self.view.window.windowScene.delegate
然而,很多时候视图控制器没有窗口.当一个视图控制器显示另一个全屏视图控制器时,就会发生这种情况.当视图控制器位于导航控制器中,而视图控制器不是顶部可见的视图控制器时,可能会发生这种情况.
这需要使用不同的方法来查找视图控制器的场景.最终,您需要结合使用漫游响应器链和视图控制器层次 struct ,直到找到通向场景的路径.
以下扩展将(可能)从视图或视图控制器获取UIScene.获得场景后,可以访问其代理.
添加UIResponder+场景.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
}
}
这可以从任何视图或视图控制器调用,以获取其场景.但请注意,只有在至少调用了viewDidAppear
次之后,才能从视图控制器获取场景.如果您尽快try ,则视图控制器可能尚未成为视图控制器层次 struct 的一部分.
即使视图控制器视图的窗口为零,只要视图控制器是视图控制器层次 struct 的一部分,并且在该层次 struct 上的某个位置,它被附加到窗口,这也会起作用.
以下是UIResponder扩展的Objective-C实现:
UIResponder+场景.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+场景.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