कैसे करें हल: iOS 13.0 में 'keyWindow' को अपदस्थ किया गया था


114

मैं क्लाउड किट के साथ कोर डेटा का उपयोग कर रहा हूं, और इसलिए एप्लिकेशन स्टार्टअप के दौरान iCloud उपयोगकर्ता की स्थिति की जांच करना है। समस्याओं के मामले में मैं उपयोगकर्ता को एक संवाद जारी करना चाहता हूं, और मैं UIApplication.shared.keyWindow?.rootViewController?.present(...)अब तक इसका उपयोग कर रहा हूं ।

Xcode 11 बीटा 4 में, अब एक नया पदावनति संदेश है, मुझे बता:

'keyWindow' को iOS 13.0 में पदावनत किया गया: इसका उपयोग उन अनुप्रयोगों के लिए नहीं किया जाना चाहिए जो कई दृश्यों का समर्थन करते हैं क्योंकि यह सभी कनेक्टेड दृश्यों में एक महत्वपूर्ण विंडो देता है

मैं इसके बजाय संवाद कैसे प्रस्तुत करूंगा?


क्या आप इसमें SceneDelegateया कर रहे हैं AppDelegate? और, क्या आप थोड़ा और कोड पोस्ट कर सकते हैं ताकि हम डुप्लिकेट कर सकें?
dfd

1
अब iOS में कोई 'कीविन्डो' कॉन्सेप्ट नहीं है क्योंकि एक ही ऐप में कई विंडो हो सकते हैं। आप अपने द्वारा बनाई गई खिड़की को स्टोर कर सकते हैं SceneDelegate(यदि आप उपयोग कर रहे हैं SceneDelegate)
सुदरा

1
@ सुदरा: इसलिए, अगर मेरे पास अभी तक कोई दृश्य नियंत्रक नहीं है, लेकिन मैं एक चेतावनी प्रस्तुत करना चाहता हूं - यह एक दृश्य के साथ कैसे करें? दृश्य कैसे प्राप्त करें, ताकि इसके rootViewController को पुनः प्राप्त किया जा सके? (तो, इसे छोटा करने के लिए: UIApplication के लिए "साझा" के बराबर दृश्य क्या है?)
हार्डी

जवाबों:


95

यह मेरा समाधान है:

let keyWindow = UIApplication.shared.connectedScenes
        .filter({$0.activationState == .foregroundActive})
        .map({$0 as? UIWindowScene})
        .compactMap({$0})
        .first?.windows
        .filter({$0.isKeyWindow}).first

उपयोग उदाहरण:

keyWindow?.endEditing(true)

4
धन्यवाद - ऐसा कुछ नहीं जो यह पता लगाने के लिए बहुत सहज हो ... 8-)
हार्डी

इस बीच मैंने कई सीन सैंपल ( डेवलपर.apple.com/documentation/uikit/app_and_environment/… ) के साथ दृष्टिकोण का परीक्षण किया और सभी ने उम्मीद के मुताबिक काम किया।
बरनी

1
यहां activationStateमूल्य के लिए परीक्षण करना भी उचित हो सकता foregroundInactiveहै, जो मेरे परीक्षण में एक चेतावनी प्रस्तुत किए जाने पर मामला होगा।
ड्रू

1
@ क्या इसका परीक्षण किया जाना चाहिए क्योंकि ऐप शुरू होने पर व्यू कंट्रोलर पहले से ही दिखाई दे रहा है लेकिन अवस्था हैforegroundInactive
गारो

2
यह कोड मेरे लिए KeyWindow = nil का निर्माण करता है। mattसमाधान वह है जो काम करता है।
बतख

170

सरलता से स्वीकार किए गए उत्तर को अधिक विस्तृत किया जा सकता है। आप वास्तव में एक ही परिणाम बहुत अधिक बस प्राप्त कर सकते हैं:

UIApplication.shared.windows.filter {$0.isKeyWindow}.first

मैं यह भी आगाह करूंगा कि इस पदावनति का keyWindow अधिक गंभीरता से नहीं लिया जाना चाहिए। पूर्ण चेतावनी संदेश पढ़ता है:

'keyWindow' को iOS 13.0 में पदावनत किया गया: इसका उपयोग उन अनुप्रयोगों के लिए नहीं किया जाना चाहिए जो कई दृश्यों का समर्थन करते हैं क्योंकि यह सभी कनेक्टेड दृश्यों में एक महत्वपूर्ण विंडो देता है

इसलिए यदि आप iPad पर कई खिड़कियों का समर्थन नहीं कर रहे हैं तो आगे जाने और उपयोग करने के लिए जारी रखने में कोई आपत्ति नहीं है keyWindow


आप इस तरह से एक सेगमेंट को कैसे संभालेंगे let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "homeVC") as! UITabBarController UIApplication.shared.keyWindow?.rootViewController = vcक्योंकि iOS 13 और कार्ड व्यू के साथ यह एक समस्या बन जाती है क्योंकि यह कहने के बाद कि कोई उपयोगकर्ता लॉग आउट करने के लिए मुख्य स्क्रीन के साथ लॉगिन स्क्रीन पर पुश हो जाएगा, जहां वे नीचे स्वाइप कर सकते हैं और वापस आ सकते हैं समस्याग्रस्त है।
लुकास बिम्बा

1
@Mario यह विंडो ऐरे में पहली विंडो नहीं है। यह विंडो ऐरे में पहली कुंजी विंडो है।
मैट

1
@Mario लेकिन सवाल यह है कि वहाँ केवल एक दृश्य है। हल की जा रही समस्या केवल एक निश्चित संपत्ति का अवमूल्यन है। स्पष्ट रूप से जीवन बहुत अधिक जटिल है यदि आपके पास वास्तव में iPad पर कई खिड़कियां हैं! यदि आप वास्तव में एक से अधिक विंडो iPad ऐप लिखने की कोशिश कर रहे हैं, तो आपके लिए शुभकामनाएं।
मैट

1
@ramzesenok बेशक यह बेहतर हो सकता है। लेकिन यह गलत नहीं है। इसके विपरीत, मुझे यह सुझाव देने वाला पहला व्यक्ति था कि यह एक खिड़की के लिए आवेदन पूछने के लिए पर्याप्त हो सकता है जो कि मुख्य खिड़की है, इस प्रकार keyWindowसंपत्ति के अपवित्रीकरण से बचा जाता है। इसलिए अपवित्र होता है। यदि आपको यह पसंद नहीं है, तो इसे डाउनवोट करें। लेकिन मुझे किसी और के जवाब से मेल करने के लिए इसे बदलने के लिए मत कहो; जैसा कि मैंने कहा, गलत होगा।
मैट

5
इसे अब सरल भी किया जा सकता हैUIApplication.shared.windows.first(where: \.isKeyWindow)
दादलार

62

मैट के उत्कृष्ट उत्तर पर थोड़ा सुधार, यह और भी सरल, छोटा और अधिक सुरुचिपूर्ण है:

UIApplication.shared.windows.first { $0.isKeyWindow }

1
धन्यवाद! क्या उद्देश्य सी में ऐसा करने का कोई तरीका है?
एलनकटव

1
@Allenktv दुर्भाग्य से NSArrayइसके बराबर नहीं है first(where:)। आप एक-लाइनर के साथ रचना करने की कोशिश कर सकते हैं filteredArrayUsingPredicate:और firstObject:
पम्मी

1
@Allenktv कमेंट सेक्शन में कोड हो गया, इसलिए मैंने नीचे एक ऑब्जेक्टिव-सी पोस्ट किया।
user2002649

Xcode 11.2 संकलक ने इस उत्तर के साथ एक त्रुटि की सूचना दी, और इसमें कोष्ठक जोड़ने का सुझाव दिया और इसके लिए सामग्री है first(where:):UIApplication.shared.windows.first(where: { $0.isKeyWindow })
Yassine ElBadaoui

1
इसे अब सरल भी किया जा सकता हैUIApplication.shared.windows.first(where: \.isKeyWindow)
दादलार

25

यह पता लगाने का एक पिछड़ा-संगत तरीका है 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
}

2
यह सबसे सुंदर उत्तर है और यह दर्शाता है कि स्विफ्ट कितनी सुंदर है extension। Ton
क्लिफ्टन

1
उपलब्धता चेक, शायद ही आवश्यक हैं के बाद से windowsऔर isKeyWindowआईओएस 2.0 के बाद से आसपास किया गया है, और first(where:)4 Xcode 9.0 / स्विफ्ट के बाद से / 2017
pommy

UIApplication.keyWindowiOS 13.0: @ अवेलेबल (iOS, पेश किया गया: 2.0, पदावनत: 13.0, संदेश: "को ऐसे दृश्यों के लिए उपयोग नहीं किया जाना चाहिए जो कई दृश्यों का समर्थन करते हैं क्योंकि यह सभी कनेक्टेड दृश्यों में एक महत्वपूर्ण विंडो लौटाता है)
वाड्रा बुलविन

15

आमतौर पर उपयोग करते हैं

स्विफ्ट 5

UIApplication.shared.windows.filter {$0.isKeyWindow}.first

UIViewController में इसके अलावा:

self.view.window

view.window cenes के लिए वर्तमान विंडो है

WWDC 2019: यहां छवि विवरण दर्ज करें

की विंडोज

  • खिड़कियों को मैन्युअल रूप से ट्रैक करें

14

एक उद्देश्य-सी समाधान के लिए

+(UIWindow*)keyWindow
{
    UIWindow        *foundWindow = nil;
    NSArray         *windows = [[UIApplication sharedApplication]windows];
    for (UIWindow   *window in windows) {
        if (window.isKeyWindow) {
            foundWindow = window;
            break;
        }
    }
    return foundWindow;
}

10

आदर्श रूप से, क्योंकि यह पदावनत किया गया है, मैं आपको सीनडेलेगेट में खिड़की को स्टोर करने की सलाह दूंगा। हालाँकि यदि आप एक अस्थायी वर्कअराउंड चाहते हैं, तो आप एक फ़िल्टर बना सकते हैं और इस तरह से कीविन्डो को पुनः प्राप्त कर सकते हैं।

let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first

9

एक 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

2

उस के साथ प्रयास करें:

UIApplication.shared.windows.filter { $0.isKeyWindow }.first?.rootViewController!.present(alert, animated: true, completion: nil)

1
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;
            }
        }
    }
}

1

एक उद्देश्य-सी समाधान के लिए भी

@implementation UIWindow (iOS13)

+ (UIWindow*) keyWindow {
   NSPredicate *isKeyWindow = [NSPredicate predicateWithFormat:@"isKeyWindow == YES"];
   return [[[UIApplication sharedApplication] windows] filteredArrayUsingPredicate:isKeyWindow].firstObject;
}

@end

1
- (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;
}

1

यदि आप इसे किसी ViewController में उपयोग करना चाहते हैं तो आप बस उपयोग कर सकते हैं।

self.view.window

0

बर्नी के उत्तर से प्रेरित

let keyWindow = Array(UIApplication.shared.connectedScenes)
        .compactMap { $0 as? UIWindowScene }
        .flatMap { $0.windows }
        .first(where: { $0.isKeyWindow })

0

डेवलपर्स के रूप में कई इस निकासी के प्रतिस्थापन के उद्देश्य सी कोड के लिए पूछ रहे हैं । 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;

-1

मैं उसी समस्या से मिला। मैंने 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;
}

आशा करता हूँ की ये काम करेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.