我使用核心数据与云工具包,因此要检查iCloud用户状态在应用程序启动。如果出现问题,我想向用户发出一个对话框,我使用UIApplication.shared.keyWindow?. rootviewcontroller ?.present(…)到目前为止。

在Xcode 11 beta 4中,现在有一个新的弃用消息,告诉我:

'keyWindow'在iOS 13.0中已弃用:不应该用于支持多个场景的应用程序,因为它在所有连接的场景中返回一个键窗口

我应该如何呈现对话呢?


当前回答

Objective C解决方案:

UIWindow *foundWindow = nil;
NSSet *scenes=[[UIApplication sharedApplication] connectedScenes];
NSArray *windows;
for(id aScene in scenes){  // it's an NSSet so you can't use the first object
    windows=[aScene windows];
    if([aScene activationState]==UISceneActivationStateForegroundActive)
         break;
}
for (UIWindow  *window in windows) {
    if (window.isKeyWindow) {
        foundWindow = window;
        break;
    }
}
 // and to find the parent viewController:
UIViewController* parentController = foundWindow.rootViewController;
while( parentController.presentedViewController &&
      parentController != parentController.presentedViewController ){
    parentController = parentController.presentedViewController;
}

其他回答

如果你想在任何ViewController中使用它,那么你可以简单地使用。

self.view.window

iOS 16,兼容至iOS 15

由于这个帖子在三年后仍有流量,我想分享我认为目前功能最优雅的解决方案。它也适用于SwiftUI。

UIApplication
    .shared
    .connectedScenes
    .compactMap { ($0 as? UIWindowScene)?.keyWindow }
    .first

iOS 15和16,兼容至iOS 13

UIApplication
    .shared
    .connectedScenes
    .flatMap { ($0 as? UIWindowScene)?.windows ?? [] }
    .first { $0.isKeyWindow }

注意,connectedScenes只在iOS 13之后才可用。如果你需要支持早期版本的iOS,你必须把这个放在If #available(iOS 13, *)语句中。

变体:更长,但更容易理解的变体:

UIApplication
    .shared
    .connectedScenes
    .compactMap { $0 as? UIWindowScene }
    .flatMap { $0.windows }
    .first { $0.isKeyWindow }

iOS 13和14

下面的历史答案在iOS 15上仍然有效,但应该被替换,因为UIApplication.shared.windows已弃用。感谢@matt指出这一点!

最初的回答:

在matt的精彩回答基础上稍作改进,这个回答更简单、更简短、更优雅:

UIApplication.shared.windows.first { $0.isKeyWindow }

下面是一个向后兼容的检测keyWindow的方法:

extension UIWindow {
    static var key: UIWindow? {
        if #available(iOS 13, *) {
            return UIApplication.shared.windows.first { $0.isKeyWindow }
        } else {
            return UIApplication.shared.keyWindow
        }
    }
}

用法:

if let keyWindow = UIWindow.key {
    // Do something
}

这是我的解决方案:

let keyWindow = UIApplication.shared.connectedScenes
        .filter({$0.activationState == .foregroundActive})
        .compactMap({$0 as? UIWindowScene})
        .first?.windows
        .filter({$0.isKeyWindow}).first

使用如:

keyWindow?.endEditing(true)

我的解决方案如下,适用于iOS 15

let window = (UIApplication.shared.connectedScenes.first as? UIWindowScene)?.windows.first