当连接多个场景时,我在获取当前UIScene
时遇到问题。
具体来说,我的应用程序(iOS 13(支持iPad上的多个窗口。当我有两个并排窗口并且我访问应用程序连接的场景(带有UIApplication.shared.connectedScenes
(时,它们都将activationState
设置为.foregroundActive
。但我实际上只与其中一个互动。
我在stackoverflow上找到了一些代码来检索当前密钥窗口(不记得是谁发布了它(,但正如你所看到的,它将始终返回两个窗口之一。
let keyWindow: UIWindow? = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
我是否缺少一些方法来确定与之交互的最后一个窗口,或者多个.foregroundActive
状态是否为错误?
谢谢!
尽管 Apple 在 iOS 13.0 之后弃用了UIApplication.shared.keyWindow
,但似乎此属性可以帮助您在前景中的多个场景时使用以下方法找到活动场景:
UIApplication.shared.keyWindow?.windowScene
我通过重构代码找到了解决问题的方法,以便现在我通过任何视图或视图控制器的window
属性访问当前UIScene
窗口。这样我就不再需要keyWindow
了。
我认为相邻打开的两个窗口都有activationState
.foregroundActive
可能是正确的
如果有人需要它,这两个扩展程序帮助我从应用程序中的任何位置进入当前窗口:
extension UIViewController {
var window: UIWindow? {
return view.window
}
}
extension UIScene {
var window: UIWindow? {
return (delegate as? SceneDelegate)?.window
}
}
但是,如果您无法访问UIView
,UIViewController
或UIScene
,则问题仍然存在。例如,在不引用视图或场景的数据模型中。然后,我看不到始终如一地访问用户正在与之交互的正确窗口的方法。
我在项目中使用此扩展
// MARK: - Scene Delegate helpers
@available(iOS 13.0, *)
extension UIApplication {
static var firstScene: UIScene? {
UIApplication.shared.connectedScenes.first
}
static var firstSceneDelegate: SceneDelegate? {
UIApplication.firstScene?.delegate as? SceneDelegate
}
static var firstWindowScene: UIWindowScene? {
UIApplication.firstSceneDelegate?.windowScene
}
}
// MARK: - Window Scene sugar
@available(iOS 13.0, *)
protocol WindowSceneDependable {
var windowScene: UIWindowScene? { get }
var window: UIWindow? { get }
}
@available(iOS 13.0, *)
extension WindowSceneDependable {
var windowScene: UIWindowScene? {
window?.windowScene
}
}
@available(iOS 13.0, *)
extension UIScene: WindowSceneDependable { }
@available(iOS 13.0, *)
extension SceneDelegate: WindowSceneDependable { }
@available(iOS 13.0, *)
extension UIViewController: WindowSceneDependable { }
// MARK: - Window sugar
@available(iOS 13.0, *)
extension UIScene {
var window: UIWindow? {
(delegate as? SceneDelegate)?.window
}
}
extension UIViewController {
var window: UIWindow? {
view.window
}
}
然后,当我必须展示一些东西时,我可以这样做:
func present(from navigation: UINavigationController) {
self.navigation = navigation
if #available(iOS 13.0, *) {
guard let currentWindowScene = navigation.windowScene else { return }
myPresenter.present(in: currentWindowScene)
} else {
myPresenter.present()
}
}
使用它,我几乎可以从任何地方获得一个窗口。但问题是,如果我根本无法访问与视图相关的对象,这是不可能的。例如,在我的身份验证服务中,我必须使用这个废话:
func authorize() {
if #available(iOS 13.0, *) {
guard let currentWindowScene = UIApplication.firstWindowScene else { return }
presenter.present(in: currentWindowScene)
} else {
presenter.present()
}
}
这对我来说看起来不正确,它仅适用于第一个窗口场景。 最好不要像我一样这样做,您必须详细说明此解决方案。
此解决方案为您提供了最后一次交互UIScene
,而无需依赖任何东西,而是对所有场景使用UIWindow
子类。
class Window: UIWindow
{
static var lastActive: Window?
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView?
{
Self.lastActive = self
return super.hitTest(point, with: event)
}
}
现在您可以访问Window.lastActive
及其关联的windowScene
(UIWindowScene
/UIScene
(。