Używam Core Data z Cloud Kit i dlatego muszę sprawdzać status użytkownika iCloud podczas uruchamiania aplikacji. W przypadku problemów chcę wywołać okno dialogowe dla użytkownika i robię to za pomocąUIApplication.shared.keyWindow?.rootViewController?.present(...)
do tej pory.
W Xcode 11 beta 4 jest teraz nowy komunikat o wycofaniu, który mówi mi:
„keyWindow” został wycofany w iOS 13.0: nie powinien być używany dla aplikacji obsługujących wiele scen, ponieważ zwraca okno klucza we wszystkich połączonych scenach
Jak mam zamiast tego przedstawić okno dialogowe?
SceneDelegate
lubAppDelegate
? Czy możesz opublikować trochę więcej kodu, abyśmy mogli powielić?SceneDelegate
(jeśli używaszSceneDelegate
)Odpowiedzi:
To jest moje rozwiązanie:
let keyWindow = UIApplication.shared.connectedScenes .filter({$0.activationState == .foregroundActive}) .map({$0 as? UIWindowScene}) .compactMap({$0}) .first?.windows .filter({$0.isKeyWindow}).first
Użycie np:
keyWindow?.endEditing(true)
źródło
activationState
wartościforegroundInactive
, co w moich testach będzie miało miejsce, jeśli zostanie przedstawiony alert.foregroundInactive
matt
rozwiązaniem jest to, które działa.Przyjęta odpowiedź, choć genialna, może być zbyt skomplikowana. Możesz uzyskać dokładnie ten sam wynik o wiele prościej:
UIApplication.shared.windows.filter {$0.isKeyWindow}.first
Chciałbym również przestrzec, że deprecjacji
keyWindow
nie należy traktować zbyt poważnie. Pełny komunikat ostrzegawczy brzmi:Więc jeśli nie obsługujesz wielu okien na iPadzie, nie ma nic przeciwko kontynuowaniu i dalszym korzystaniu
keyWindow
.źródło
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "homeVC") as! UITabBarController UIApplication.shared.keyWindow?.rootViewController = vc
ponieważ w przypadku iOS 13 i widoku karty staje się to problemem, ponieważ użytkownik po powiedzeniu wylogowania zostanie przeniesiony do ekranu logowania z główną aplikacją w hierarchii widoków, gdzie może przesunąć w dół i powrócić jest problematyczne.keyWindow
właściwości. Stąd głosy poparcia. Jeśli ci się to nie podoba, oceń to. Ale nie mów mi, żebym go zmienił, aby pasował do cudzej odpowiedzi; to, jak powiedziałem, byłoby złe.UIApplication.shared.windows.first(where: \.isKeyWindow)
Poprawiając nieznacznie doskonałą odpowiedź Matta, jest jeszcze prostsza, krótsza i bardziej elegancka:
UIApplication.shared.windows.first { $0.isKeyWindow }
źródło
NSArray
nie ma odpowiednikafirst(where:)
. Możesz spróbować skomponować jedną linijkę za pomocąfilteredArrayUsingPredicate:
ifirstObject:
.first(where:)
:UIApplication.shared.windows.first(where: { $0.isKeyWindow })
UIApplication.shared.windows.first(where: \.isKeyWindow)
Oto kompatybilny wstecz sposób wykrywania
keyWindow
:extension UIWindow { static var key: UIWindow? { if #available(iOS 13, *) { return UIApplication.shared.windows.first { $0.isKeyWindow } } else { return UIApplication.shared.keyWindow } } }
Stosowanie:
if let keyWindow = UIWindow.key { // Do something }
źródło
extension
. 🙂windows
iisKeyWindow
mają już od iOS 2.0 ifirst(where:)
od 9.0 Xcode Swift / 4/2017UIApplication.keyWindow
został wycofany w iOS 13.0: @available (iOS, wprowadzono: 2.0, wycofano: 13.0, komunikat: „Nie należy używać w aplikacjach obsługujących wiele scen, ponieważ zwraca okno klucza we wszystkich połączonych scenach”)Zwykle używaj
Szybki 5
UIApplication.shared.windows.filter {$0.isKeyWindow}.first
Dodatkowo , w UIViewController:
self.view.window
view.window
jest bieżącym oknem dla scenWWDC 2019:
źródło
Rozwiązanie 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; }
źródło
nullable
do deklaracji nagłówka!UIApplication
Rozszerzenie:extension UIApplication { /// The app's key window taking into consideration apps that support multiple scenes. var keyWindowInConnectedScenes: UIWindow? { return windows.first(where: { $0.isKeyWindow }) } }
Stosowanie:
let myKeyWindow: UIWindow? = UIApplication.shared.keyWindowInConnectedScenes
źródło
Byłoby idealnie, ponieważ zostało wycofane, radziłbym przechowywać okno w SceneDelegate. Jeśli jednak chcesz tymczasowego obejścia problemu, możesz utworzyć filtr i pobrać keyWindow w ten sposób.
let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
źródło
spróbuj z tym:
UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.rootViewController!.present(alert, animated: true, completion: nil)
źródło
Jeśli chcesz go używać w dowolnym kontrolerze ViewController, możesz po prostu użyć.
self.view.window
źródło
Również dla rozwiązania Objective-C
@implementation UIWindow (iOS13) + (UIWindow*) keyWindow { NSPredicate *isKeyWindow = [NSPredicate predicateWithFormat:@"isKeyWindow == YES"]; return [[[UIApplication sharedApplication] windows] filteredArrayUsingPredicate:isKeyWindow].firstObject; } @end
źródło
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; } } } }
źródło
- (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; }
źródło
Spotkałem ten sam problem. Przydzieliłem a
newWindow
do widoku i ustawiłem go.[newWindow makeKeyAndVisible];
Kiedy skończyłem go używać, ustaw go,[newWindow resignKeyWindow];
a następnie spróbuj bezpośrednio wyświetlić oryginalne okno-klawisza[UIApplication sharedApplication].keyWindow
.Na iOS 12 wszystko jest w porządku, ale na iOS 13 oryginalne okno klucza nie zostało normalnie pokazane. Pokazuje cały biały ekran.
Rozwiązałem ten problem poprzez:
UIWindow *mainWindow = nil; if ( @available(iOS 13.0, *) ) { mainWindow = [UIApplication sharedApplication].windows.firstObject; [mainWindow makeKeyWindow]; } else { mainWindow = [UIApplication sharedApplication].keyWindow; }
Mam nadzieję, że to pomoże.
źródło
Zainspirowany odpowiedzią berni
let keyWindow = Array(UIApplication.shared.connectedScenes) .compactMap { $0 as? UIWindowScene } .flatMap { $0.windows } .first(where: { $0.isKeyWindow })
źródło
Ponieważ wielu programistów prosi o kod Objective C, który zastąpił to wycofanie. Możesz użyć poniższego kodu, aby użyć keyWindow.
+(UIWindow*)keyWindow { UIWindow *windowRoot = nil; NSArray *windows = [[UIApplication sharedApplication]windows]; for (UIWindow *window in windows) { if (window.isKeyWindow) { windowRoot = window; break; } } return windowRoot; }
Stworzyłem i dodałem tę metodę w
AppDelegate
klasie jako metodę klasową i używam jej w bardzo prosty sposób, który jest poniżej.[AppDelegate keyWindow];
Nie zapomnij dodać tej metody do klasy AppDelegate.h, jak poniżej.
+(UIWindow*)keyWindow;
źródło