在iOS 13.0及更高版本中,keyWindow 属性被弃用,原因是为了支持多场景(scenes)的应用程序,因为它会返回所有连接场景的关键窗口。这意味着在支持多窗口的应用中,直接使用 keyWindow 可能会导致不可预测的行为或错误的结果。因此,开发者需要寻找更安全的替代方案来获取当前窗口。
替代方案
1. 使用 UIApplication.shared.windows 获取窗口列表
在iOS 13及更高版本中,可以使用 UIApplication.shared.windows 来获取所有窗口的列表,然后从中筛选出当前的关键窗口(key window)。
UIWindow *keyWindow = nil;
NSArray *windows = [[UIApplication sharedApplication] windows];
for (UIWindow *window in windows) {
if (window.isKeyWindow) {
keyWindow = window;
break;
}
}
或者更简洁的方式:
UIWindow *keyWindow = [[UIApplication sharedApplication].windows firstObject];
但是,这种方法在iOS 15及更高版本中可能会被弃用,因此需要进一步优化。
2. 使用 UIApplication.shared.connectedScenes 获取当前活动的场景
从iOS 13开始,推荐使用 UIApplication.shared.connectedScenes 来获取当前连接的场景,然后从中筛选出前台活动的场景,并获取其窗口列表。
UIWindow *keyWindow = nil;
for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
if ([scene isKindOfClass:[UIWindowScene class]] && scene.activationState == UISceneActivationStateForegroundActive) {
UIWindowScene *windowScene = (UIWindowScene *)scene;
for (UIWindow *window in windowScene.windows) {
if (window.isKeyWindow) {
keyWindow = window;
break;
}
}
}
}
更简洁的方式:
UIWindow *keyWindow = [[[UIApplication sharedApplication].connectedScenes filter:^BOOL(UIScene * _Nonnull obj) {
return obj.activationState == UISceneActivationStateForegroundActive;
}] firstObject].windows.firstObject];
3. 使用 UIWindowScene.windows 获取特定场景的窗口
在iOS 15及更高版本中,推荐使用 UIWindowScene.windows 来获取特定场景的窗口列表。
UIWindow *keyWindow = nil;
for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
if ([scene isKindOfClass:[UIWindowScene class]] && scene.activationState == UISceneActivationStateForegroundActive) {
UIWindowScene *windowScene = (UIWindowScene *)scene;
keyWindow = [windowScene.windows firstObject];
break;
}
}
更简洁的方式:
UIWindow *keyWindow = [[[UIApplication sharedApplication].connectedScenes filter:^BOOL(UIScene * _Nonnull obj) {
return obj.activationState == UISceneActivationStateForegroundActive;
}] firstObject].windows.firstObject];
示例代码
以下是一个综合示例代码,适用于iOS 13及更高版本:
- (UIWindow *)getKeyWindow {
if (@available(iOS 13.0, *)) {
for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
if ([scene isKindOfClass:[UIWindowScene class]] && scene.activationState == UISceneActivationStateForegroundActive) {
UIWindowScene *windowScene = (UIWindowScene *)scene;
for (UIWindow *window in windowScene.windows) {
if (window.isKeyWindow) {
return window;
}
}
}
}
} else {
return [UIApplication sharedApplication].keyWindow;
}
return nil;
}
总结
为了适应iOS 13及更高版本中的多场景支持,开发者应避免使用已弃用的 keyWindow 属性,而是使用 UIApplication.shared.windows 或 UIApplication.shared.connectedScenes 来获取当前的关键窗口。这样可以确保应用程序在多窗口环境下正常运行,并避免潜在的崩溃或错误。