Swift 如何解决:';钥匙窗';在iOS 13.0中被弃用
我正在使用云工具包的核心数据,因此必须在应用程序启动期间检查iCloud用户状态。如果出现问题,我想向用户发出一个对话框,我使用Swift 如何解决:';钥匙窗';在iOS 13.0中被弃用,swift,ios13,uiwindow,uiscene,Swift,Ios13,Uiwindow,Uiscene,我正在使用云工具包的核心数据,因此必须在应用程序启动期间检查iCloud用户状态。如果出现问题,我想向用户发出一个对话框,我使用UIApplication.shared.keyWindow?.rootViewController?.present(…)到目前为止 在Xcode 11 beta 4中,现在有一条新的弃用消息,告诉我: iOS 13.0中不推荐使用“keyWindow”:不应用于支持多个场景的应用程序,因为它会在所有连接的场景中返回一个关键窗口 如何显示该对话框?这是我的解决方案:
UIApplication.shared.keyWindow?.rootViewController?.present(…)
到目前为止
在Xcode 11 beta 4中,现在有一条新的弃用消息,告诉我:
iOS 13.0中不推荐使用“keyWindow”:不应用于支持多个场景的应用程序,因为它会在所有连接的场景中返回一个关键窗口
如何显示该对话框?这是我的解决方案:
let keyWindow = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
用法,例如:
keyWindow?.endEditing(true)
公认的答案虽然巧妙,但可能过于复杂。您可以更简单地得到完全相同的结果:
UIApplication.shared.windows.filter {$0.isKeyWindow}.first
我还要提醒大家,不要过于严肃地对待keyWindow
的弃用。完整的警告信息如下:
iOS 13.0中不推荐使用“keyWindow”:不应用于支持多个场景的应用程序,因为它会在所有连接的场景中返回一个关键窗口
因此,如果您不支持iPad上的多个窗口,那么继续使用
keyWindow
对matt的优秀答案稍加改进,这将更加简单、简短、优雅:
UIApplication.shared.windows.first { $0.isKeyWindow }
理想情况下,由于它已被弃用,我建议您将窗口存储在SceneDelegate中。但是,如果确实需要临时解决方法,可以创建一个过滤器并检索keyWindow,如下所示
let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
对于一个Objective-C解决方案
+(UIWindow*)keyWindow
{
UIWindow *foundWindow = nil;
NSArray *windows = [[UIApplication sharedApplication]windows];
for (UIWindow *window in windows) {
if (window.isKeyWindow) {
foundWindow = window;
break;
}
}
return foundWindow;
}
我遇到了同样的问题。
我为一个视图分配了一个newWindow
,并将其设置为[newwindowmakeyAndVisible]代码>
使用完毕后,将其设置为[newWindow resignKeyWindow]代码>
然后尝试通过[UIApplication sharedApplication].keyWindow直接显示原始密钥窗口
在iOS 12上一切正常,但在iOS 13上无法正常显示原始密钥窗口。它显示了一个完整的白色屏幕
我通过以下方式解决了这个问题:
UIWindow *mainWindow = nil;
if ( @available(iOS 13.0, *) ) {
mainWindow = [UIApplication sharedApplication].windows.firstObject;
[mainWindow makeKeyWindow];
} else {
mainWindow = [UIApplication sharedApplication].keyWindow;
}
希望有帮助。Aui应用程序
扩展:
extension UIApplication {
/// The app's key window taking into consideration apps that support multiple scenes.
var keyWindowInConnectedScenes: UIWindow? {
return windows.first(where: { $0.isKeyWindow })
}
}
用法:
let myKeyWindow: UIWindow? = UIApplication.shared.keyWindowInConnectedScenes
灵感来源于
以下是一种向后兼容的检测keyWindow
的方法:
扩展窗口{
静态变量键:UIWindow{
如果可用(iOS 13,*){
返回UIApplication.shared.windows.first{$0.isKeyWindow}
}否则{
返回UIApplication.shared.keyWindow
}
}
}
用法:
let myKeyWindow: UIWindow? = UIApplication.shared.keyWindowInConnectedScenes
如果let keyWindow=UIWindow.key{
//做点什么
}
试试看:
UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.rootViewController!.present(alert, animated: true, completion: nil)
常用
斯威夫特5
UIApplication.shared.windows.filter {$0.isKeyWindow}.first
此外,在UIViewController中:
self.view.window
view.window
是场景的当前窗口
WWDC 2019:
关键窗口
- 手动跟踪窗口
也适用于Objective-C解决方案
@implementation UIWindow (iOS13)
+ (UIWindow*) keyWindow {
NSPredicate *isKeyWindow = [NSPredicate predicateWithFormat:@"isKeyWindow == YES"];
return [[[UIApplication sharedApplication] windows] filteredArrayUsingPredicate:isKeyWindow].firstObject;
}
@end
正如许多开发人员要求用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;
如果您想在任何ViewController中使用它,只需使用
self.view.window
Berni的代码很好,但当应用程序从后台返回时,它就不起作用了
这是我的代码:
class var safeArea : UIEdgeInsets
{
if #available(iOS 13, *) {
var keyWindow = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
// <FIX> the above code doesn't work if the app comes back from background!
if (keyWindow == nil) {
keyWindow = UIApplication.shared.windows.first { $0.isKeyWindow }
}
return keyWindow?.safeAreaInsets ?? UIEdgeInsets()
}
else {
guard let keyWindow = UIApplication.shared.keyWindow else { return UIEdgeInsets() }
return keyWindow.safeAreaInsets
}
}
类别变量安全区域:UIEdgeInsets
{
如果可用(iOS 13,*){
var keyWindow=UIApplication.shared.connectedScenes
.filter({$0.activationState==.foregroundActive})
.map({$0 as?UIWindowScene})
.compactMap({$0})
.第一个?.窗户
.filter({$0.isKeyWindow})
//如果应用程序从后台返回,上述代码将不起作用!
如果(keyWindow==nil){
keyWindow=UIApplication.shared.windows.first{$0.isKeyWindow}
}
返回键窗口?.safeAreaInsets??UIEdgeInsets()
}
否则{
guard let keyWindow=UIApplication.shared.keyWindow else{return UIEdgeInsets()}
返回键窗口。安全区域插图
}
}
您是在SceneDelegate
还是AppDelegate
中执行此操作?还有,你能不能多发一点代码,这样我们就可以复制了?iOS中不再有“keyWindow”的概念,因为一个应用程序可以有多个窗口。您可以将创建的窗口存储在SceneDelegate
(如果您使用的是SceneDelegate
)@Sudara:那么,如果我还没有视图控制器,但想发出警报-如何处理场景?如何获取场景,以便可以检索其rootViewController?(所以,简而言之:什么场景相当于UIApplication的“共享”场景?)。。。8-)您只需使用getisKeyWindow
。在此处测试activationState
值foregroundInactive
也可能是合适的,在我的测试中,如果出现警报,就会出现这种情况。@Drew应该对其进行测试,因为在应用程序启动时,视图控制器已可见,但状态为foregroundInactive
此代码为我生成keyWindow=nil<代码>马特
解决方案才是有效的。谢谢!在目标c中有办法做到这一点吗?@Allenktv不幸的是NSArray
没有与first(其中:)
等效的方法。您可以尝试用filteredarrayingpredicate:
和firstObject:
@allinktv组成一个单行程序。代码在注释部分被弄乱了,所以我在下面发布了一个Objective-C等价物。Xcode 11.2编译器报告了一个错误,并建议首先在中添加括号及其内容(其中:)
:UIApplication.shared.windows.first(其中:{$0.i
self.view.window
class var safeArea : UIEdgeInsets
{
if #available(iOS 13, *) {
var keyWindow = UIApplication.shared.connectedScenes
.filter({$0.activationState == .foregroundActive})
.map({$0 as? UIWindowScene})
.compactMap({$0})
.first?.windows
.filter({$0.isKeyWindow}).first
// <FIX> the above code doesn't work if the app comes back from background!
if (keyWindow == nil) {
keyWindow = UIApplication.shared.windows.first { $0.isKeyWindow }
}
return keyWindow?.safeAreaInsets ?? UIEdgeInsets()
}
else {
guard let keyWindow = UIApplication.shared.keyWindow else { return UIEdgeInsets() }
return keyWindow.safeAreaInsets
}
}