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

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

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

我应该如何呈现对话呢?


当前回答

由于许多开发人员要求将Objective C代码的这种弃用进行替换。您可以使用下面的代码来使用keyWindow。

+(UIWindow*)keyWindow {
    UIWindow        *windowRoot = nil;
    NSArray         *windows = [[UIApplication sharedApplication]windows];
    for (UIWindow   *window in windows) {
        if (window.isKeyWindow) {
            windowRoot = window;
            break;
        }
    }
    return windowRoot;
}

我在AppDelegate类中创建并添加了这个方法作为类方法,并以下面的非常简单的方式使用它。

[AppDelegate keyWindow];

不要忘记像下面这样在AppDelegate.h类中添加这个方法。

+(UIWindow*)keyWindow;

其他回答

这是我的解决方案:

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

使用如:

keyWindow?.endEditing(true)

我在这里提出的建议在iOS 15中已弃用。现在怎么办?好吧,如果一个应用没有自己的多个窗口,我假设接受的现代方式将是获得应用的第一个connectedscene,强制到一个UIWindowScene,并获得它的第一个窗口。但这几乎正是公认的答案所做的!所以我的变通办法在这一点上感觉相当无力。但是,由于历史原因,我还是让它保持原样。


公认的答案虽然巧妙,但可能过于详尽。你可以更简单地得到完全相同的结果:

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

我还要提醒大家,不要过于认真地对待keyWindow的弃用。完整的警告信息如下:

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

所以如果你不支持iPad上的多窗口,继续使用keyWindow是没有异议的。

理想情况下,由于它已经被弃用,我建议你将窗口存储在SceneDelegate中。但是,如果您确实想要一个临时的解决方案,您可以创建一个过滤器并像这样检索keyWindow。

let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first

对于Objective-C解决方案也是如此

@implementation UIWindow (iOS13)

+ (UIWindow*) keyWindow {
   NSPredicate *isKeyWindow = [NSPredicate predicateWithFormat:@"isKeyWindow == YES"];
   return [[[UIApplication sharedApplication] windows] filteredArrayUsingPredicate:isKeyWindow].firstObject;
}

@end

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 }