Я использую Core Data с Cloud Kit и поэтому должен проверять статус пользователя iCloud во время запуска приложения. В случае возникновения проблем я хочу создать диалог с пользователем, и я делаю это UIApplication.shared.keyWindow?.rootViewController?.present(...)
до сих пор.
В Xcode 11 beta 4 появилось новое сообщение об отказе от поддержки, в котором говорится:
'keyWindow' устарело в iOS 13.0: не должно использоваться для приложений, поддерживающих несколько сцен, поскольку он возвращает ключевое окно для всех связанных сцен.
Как мне представить диалог вместо этого?
SceneDelegate
илиAppDelegate
? И не могли бы вы опубликовать еще немного кода, чтобы мы могли его продублировать?SceneDelegate
SceneDelegate
Ответы:
Это мое решение:
let keyWindow = UIApplication.shared.connectedScenes .filter({$0.activationState == .foregroundActive}) .map({$0 as? UIWindowScene}) .compactMap({$0}) .first?.windows .filter({$0.isKeyWindow}).first
Пример использования:
keyWindow?.endEditing(true)
источник
activationState
значениеforegroundInactive
, что в моем тестировании будет иметь место, если отображается предупреждение.foregroundInactive
matt
решение то, что работает.Принятый ответ, хотя и гениальный, может быть излишне сложным. Вы можете получить точно такой же результат намного проще:
UIApplication.shared.windows.filter {$0.isKeyWindow}.first
Я также хотел бы предостеречь, что
keyWindow
не следует воспринимать отказ от поддержки слишком серьезно. Полное предупреждение гласит:Так что, если вы не поддерживаете несколько окон на iPad, нет никаких возражений против продолжения использования
keyWindow
.источник
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "homeVC") as! UITabBarController UIApplication.shared.keyWindow?.rootViewController = vc
потому что с iOS 13 и карточным представлением это становится проблемой, потому что пользователь после выхода, скажем, будет переведен на экран входа в систему с основным приложением в иерархии представлений, где они могут провести вниз и вернуть то, что проблематично.keyWindow
свойства. Отсюда и положительные голоса. Если вам это не нравится, проголосуйте против. Но не просите меня изменить его, чтобы он соответствовал чьему-то ответу; это, как я сказал, было бы неправильно.UIApplication.shared.windows.first(where: \.isKeyWindow)
Немного улучшив отличный ответ Мэтта, он стал еще проще, короче и элегантнее:
UIApplication.shared.windows.first { $0.isKeyWindow }
источник
NSArray
, не имеет эквивалентаfirst(where:)
. Вы можете попробовать составить однострочник с помощьюfilteredArrayUsingPredicate:
иfirstObject:
.first(where:)
:UIApplication.shared.windows.first(where: { $0.isKeyWindow })
UIApplication.shared.windows.first(where: \.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 }
источник
extension
. 🙂windows
иisKeyWindow
существуют с iOS 2.0 иfirst(where:)
с Xcode 9.0 / Swift 4/2017.UIApplication.keyWindow
устарела в iOS 13.0: @available (iOS, введено: 2.0, устарело: 13.0, сообщение: «Не следует использовать для приложений, поддерживающих несколько сцен, поскольку оно возвращает ключевое окно для всех связанных сцен»)Обычно используют
Swift 5
UIApplication.shared.windows.filter {$0.isKeyWindow}.first
Вдобавок , в UIViewController:
self.view.window
view.window
текущее окно для сценWWDC 2019:
источник
Для решения 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; }
источник
nullable
в заголовок объявление!UIApplication
Расширение: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
источник
В идеале, поскольку он устарел, я бы посоветовал вам сохранить окно в SceneDelegate. Однако, если вам нужен временный обходной путь, вы можете создать фильтр и получить keyWindow точно так же.
let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
источник
попробуйте с этим:
UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.rootViewController!.present(alert, animated: true, completion: nil)
источник
Если вы хотите использовать его в любом ViewController, вы можете просто использовать.
self.view.window
источник
Для решения Objective-C тоже
@implementation UIWindow (iOS13) + (UIWindow*) keyWindow { NSPredicate *isKeyWindow = [NSPredicate predicateWithFormat:@"isKeyWindow == YES"]; return [[[UIApplication sharedApplication] windows] filteredArrayUsingPredicate:isKeyWindow].firstObject; } @end
источник
NSSet *connectedScenes = [UIApplication sharedApplication].connectedScenes; for (UIScene *scene in connectedScenes) { if (scene.activationState == UISceneActivationStateForegroundActive && [scene isKindOfClass:[UIWindowScene class]]) { UIWindowScene *windowScene = (UIWindowScene *)scene; for (UIWindow *window in windowScene.windows) { UIViewController *viewController = window.rootViewController; // Get the instance of your view controller if ([viewController isKindOfClass:[YOUR_VIEW_CONTROLLER class]]) { // Your code here... break; } } } }
источник
- (UIWindow *)mainWindow { NSEnumerator *frontToBackWindows = [UIApplication.sharedApplication.windows reverseObjectEnumerator]; for (UIWindow *window in frontToBackWindows) { BOOL windowOnMainScreen = window.screen == UIScreen.mainScreen; BOOL windowIsVisible = !window.hidden && window.alpha > 0; BOOL windowLevelSupported = (window.windowLevel >= UIWindowLevelNormal); BOOL windowKeyWindow = window.isKeyWindow; if(windowOnMainScreen && windowIsVisible && windowLevelSupported && windowKeyWindow) { return window; } } return nil; }
источник
Я встретил ту же проблему. Я выделил a
newWindow
для представления и установил его.[newWindow makeKeyAndVisible];
Когда закончил его использовать, установил его,[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; }
Надеюсь, это поможет.
источник
Вдохновленный ответом Берни
let keyWindow = Array(UIApplication.shared.connectedScenes) .compactMap { $0 as? UIWindowScene } .flatMap { $0.windows } .first(where: { $0.isKeyWindow })
источник
Как многие разработчики просят код 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;
источник