UIApplication.sharedApplication.delegate.window 和 UIApplication.sharedApplication.keyWindow 有什么区别?

40

有谁能帮我理解以下两行代码的区别:

[UIApplication.sharedApplication.delegate.window addSubview:myView];
[UIApplication.sharedApplication.keyWindow addSubview:myView];
4个回答

42

对于大多数用途,它们将是相同的...但并非总是如此。

[UIApplication sharedApplication].keyWindow 是当前在设备上显示的窗口。这通常是您的应用程序窗口,但也可能是系统窗口。

[UIApplication sharedApplication].delegate.window 是您的应用程序预期使用的窗口。

那么应该使用哪个呢?这完全取决于上下文。

如果您正在更新应用程序的某个部分,则应将视图添加到应用程序的窗口。这几乎总是您想要做的事情。

就我个人而言,当我需要直接将视图添加到窗口时,我总是使用 [[UIApplication sharedApplication].delegate.window addSubview:view][self.view.window addSubView:view](在UIViewController中)。

有时,您可能希望将视图呈现到当前显示的窗口,而不管该窗口是否属于您的应用程序或是某个系统窗口。我还没有遇到过这种情况。


由于您不知道上一个屏幕是什么...在收到远程通知时,使用keyWindow显示警报是否是个好主意?我指的是iOS10之前的iOS版本,在那里您没有willPresent - mfaani

18
它们在iOS上可能是相同的。当它们不同时,通常您会呈现应用委托的主窗口以外的另一个窗口。您的应用程序可以拥有许多窗口,但只有keyWindow是可见于屏幕并接收事件的窗口(例如,当UIAlert可见并接收事件时,它是keywindow)。参考:https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/WindowAndScreenGuide/WindowScreenRolesinApp/WindowScreenRolesinApp.html
从文档中可知:
对于UIApplication.sharedApplication.delegate.window
该属性包含用于在设备的主屏幕上呈现应用程序视觉内容的窗口,因此用于呈现故事板。
即这是您在AppDelegate.h文件中拥有的window属性。
对于UIApplication.sharedApplication.keyWindow
该属性包含在窗口数组中最近发送了makeKeyAndVisible消息的UIWindow对象。
在iOS上,在AppDelegate.m内调用makeKeyAndVisible,如下所示: application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 你使创建的应用委托窗口成为keyWindow。通常,银行应用程序在将应用程序放在后台以保护用户敏感信息时切换关键窗口,并在应用程序处于前台时切换回主委托窗口。

因为这不正确,参见Jeffrey Thomas和Andy Darwin的回答,所以被踩了。 - Sipke Schoorstra
@SipkeSchoorstra 感谢您的反馈,答案已更新。 - Basheer_CAD
这是错误的。不仅keyWindow可见,例如警报使用单独的窗口显示。当窗口当前接收键盘和非触摸相关事件时,它被认为是关键窗口。请参阅https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/WindowAndScreenGuide/WindowScreenRolesinApp/WindowScreenRolesinApp.html。 - D-Mx
1
嘿 @D-Mx,是的,看起来我忘了提到关键窗口是可见且正在接收事件,现在已更新以包括该信息。我会说答案并不是错误的,但是不完整,感谢您帮助使stackoverflow成为友好和协作的地方 :) - Basheer_CAD

7

Basheer_CAD的回答是不正确的。在iOS中它们并不总是相同的。

Jeffery Thomas的回答是正确的,让我提供一个具体的例子。

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"keyWindow --------> %@",[UIApplication sharedApplication].keyWindow.rootViewController);
    NSLog(@"delegate.window --> %@",[UIApplication sharedApplication].delegate.window.rootViewController);
    NSLog(@"self.view.window -> %@",self.view.window.rootViewController);
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:nil];
    [alert show];
    NSLog(@"keyWindow --------> %@",[UIApplication sharedApplication].keyWindow.rootViewController);
    NSLog(@"delegate.window --> %@",[UIApplication sharedApplication].delegate.window.rootViewController);
    NSLog(@"self.view.window -> %@",self.view.window.rootViewController);
}

输出结果为:
keyWindow --------> (null)
delegate.window --> <ViewController: 0x10030c0e0>
self.view.window -> (null)
keyWindow --------> <UIApplicationRotationFollowingController: 0x100204510>
delegate.window --> <ViewController: 0x10030c0e0>
self.view.window -> <ViewController: 0x10030c0e0>

viewDidLoad 时,窗口实际上还没有准备好,因此系统窗口是无法使用的。 UIAlertView 可能会占用窗口,所以你无法获取想要的窗口。


感谢您的反馈,请查看我的更新答案。因此,您的回答已经得到了赞同 :) - Basheer_CAD

4

最简单的设置就是只有一个UIWindow。通常这个窗口被保存为您的应用程序委托的属性。 keyWindow 是指定接收键盘和其他非触摸相关事件的窗口。一次只能有一个窗口成为关键窗口。因此,如果您添加第二个窗口并将其设置为keyWindow(通过[window makeKeyAndVisible]),则会返回不同的窗口!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接