AppDelegate.m में स्क्रीन पर UIViewController को प्रदर्शित करने वाला वर्तमान प्राप्त करें


126

UIViewControllerस्क्रीन पर करंट को कुछ बैज व्यू सेट करके APNs से पुश-नोटिफिकेशन का जवाब देना होगा। लेकिन मैं कैसे UIViewControllerविधि में मिल सकता है application:didReceiveRemoteNotification: का AppDelegate.m?

मैंने self.window.rootViewControllerवर्तमान प्रदर्शन प्राप्त करने के लिए उपयोग करने की कोशिश की UIViewController, यह एक UINavigationViewControllerया कुछ अन्य प्रकार का दृश्य नियंत्रक हो सकता है । और मुझे पता चला है कि स्क्रीन पर पाने के लिए visibleViewControllerसंपत्ति का UINavigationViewControllerउपयोग किया जा सकता है UIViewController। लेकिन अगर यह नहीं है तो मैं क्या कर सकता हूं UINavigationViewController?

किसी भी मदद की सराहना की है! संबंधित कोड निम्नलिखित है।

AppDelegate.m

...
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

    //I would like to find out which view controller is on the screen here.

    UIViewController *vc = [(UINavigationViewController *)self.window.rootViewController visibleViewController];
    [vc performSelector:@selector(handleThePushNotification:) withObject:userInfo];
}
...

ViewControllerA.m

- (void)handleThePushNotification:(NSDictionary *)userInfo{

    //set some badge view here

}

जवाबों:


99

rootViewControllerजब आपका नियंत्रक नहीं है तो आप इसका उपयोग भी कर सकते हैं UINavigationController:

UIViewController *vc = self.window.rootViewController;

एक बार जब आप रूट व्यू कंट्रोलर को जान लेते हैं, तो यह इस बात पर निर्भर करता है कि आपने अपना यूआई कैसे बनाया है, लेकिन आप संभवतः कंट्रोलर पदानुक्रम के माध्यम से नेविगेट करने का एक तरीका खोज सकते हैं।

यदि आप अपने ऐप को परिभाषित करने के तरीके के बारे में कुछ और जानकारी देते हैं, तो मैं कुछ और संकेत दे सकता हूं।

संपादित करें:

यदि आप सर्वोच्च दृश्य (नियंत्रक नहीं देखें) चाहते हैं, तो आप देख सकते हैं

[[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];

हालांकि यह दृश्य अदृश्य हो सकता है या इसके कुछ साक्षात्कारों द्वारा कवर किया जा सकता है ...

फिर से, यह आपके UI पर निर्भर करता है, लेकिन यह मदद कर सकता है ...


19
इसके साथ समस्या यह है कि यदि दृश्य दृश्य रूट दृश्य नियंत्रक (मोडल विचारों और इस तरह के मामले में) से संबंधित नहीं है।
दिमा

हां, है। लेकिन यह शायद एक UITabViewController है। क्या स्क्रीन पर UIViewController पाने के लिए एक सीधा तरीका नहीं है?
लू युआन

2
ठीक है, आप देखते हैं, UINavigationController आपको यह जानने का एक तरीका प्रदान करता है कि कौन सा नियंत्रक सबसे ऊपर है; आपके रूट कंट्रोलर को उसी तरह की जानकारी प्रदान करनी चाहिए। यह सामान्य रूप से अनुमान नहीं लगाया जा सकता है क्योंकि यह इस बात पर निर्भर करता है कि आपने अपना UI कैसे बनाया है और कोई स्पष्ट नियंत्रक पदानुक्रम नहीं है (जैसे कि यह विचारों के लिए होता है)। आप बस अपने रूट कंट्रोलर में एक संपत्ति जोड़ सकते हैं और इसके मूल्य को सेट कर सकते हैं जब भी आप शीर्ष पर एक नया नियंत्रक "पुश" कर सकते हैं।
सर्जियो

1
जब तक मूल्य को अद्यतन रखा जाता है, तब तक यह मेरे लिए भी एक अच्छा तरीका है।
दिमा

4
एक UIViewउदाहरण से नियंत्रक को प्राप्त करने का कोई सीधा तरीका नहीं है । rootViewControllerहै जरूरी वर्तमान में प्रदर्शित नियंत्रक। यह सिर्फ पदानुक्रम के शीर्ष पर है।
गिंगी

101

मैं हमेशा ऐसे समाधानों से प्यार करता हूं जिनमें श्रेणियां शामिल हैं क्योंकि वे बोल्ट हैं और आसानी से पुन: उपयोग किए जा सकते हैं।

इसलिए मैंने UIWindow पर एक श्रेणी बनाई। अब आप UIWindow पर दृश्य दृश्यकंट्रोलर को कॉल कर सकते हैं और यह आपको नियंत्रक पदानुक्रम की खोज करके दृश्य दृश्य नियंत्रक प्राप्त करेगा। यदि आप नेविगेशन और / या टैब बार कंट्रोलर का उपयोग कर रहे हैं तो यह काम करता है। यदि आपके पास सुझाव देने के लिए अन्य प्रकार का नियंत्रक है तो कृपया मुझे बताएं और मैं इसे जोड़ सकता हूं।

UIWindow + PazLabs.h (हेडर फ़ाइल)

#import <UIKit/UIKit.h>

@interface UIWindow (PazLabs)

- (UIViewController *) visibleViewController;

@end

UIWindow + PazLabs.m (कार्यान्वयन फ़ाइल)

#import "UIWindow+PazLabs.h"

@implementation UIWindow (PazLabs)

- (UIViewController *)visibleViewController {
    UIViewController *rootViewController = self.rootViewController;
    return [UIWindow getVisibleViewControllerFrom:rootViewController];
}

+ (UIViewController *) getVisibleViewControllerFrom:(UIViewController *) vc {
    if ([vc isKindOfClass:[UINavigationController class]]) {
        return [UIWindow getVisibleViewControllerFrom:[((UINavigationController *) vc) visibleViewController]];
    } else if ([vc isKindOfClass:[UITabBarController class]]) {
        return [UIWindow getVisibleViewControllerFrom:[((UITabBarController *) vc) selectedViewController]];
    } else {
        if (vc.presentedViewController) {
            return [UIWindow getVisibleViewControllerFrom:vc.presentedViewController];
        } else {
            return vc;
        }
    }
}

@end

स्विफ्ट संस्करण

public extension UIWindow {
    public var visibleViewController: UIViewController? {
        return UIWindow.getVisibleViewControllerFrom(self.rootViewController)
    }

    public static func getVisibleViewControllerFrom(_ vc: UIViewController?) -> UIViewController? {
        if let nc = vc as? UINavigationController {
            return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController)
        } else if let tc = vc as? UITabBarController {
            return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController)
        } else {
            if let pvc = vc?.presentedViewController {
                return UIWindow.getVisibleViewControllerFrom(pvc)
            } else {
                return vc
            }
        }
    }
}

2
मैं स्विफ्ट संस्करण के लिए इसका उपयोग कैसे कर सकता हूं?
विजय सिंह राणा

2
मैं आपके सवाल को नहीं समझ सकता। अपने कोड के अंदर कॉपी और पेस्ट करें।
जिरिनिस्प

कस्टम कंटेनर कुलपति के बारे में क्या?
मिंगमिंग

@Mingming यह मुश्किल नहीं होना चाहिए कि अगर अतिरिक्त कस्टम कंटेनर VC (getVisibielController विधि में) की जाँच करें और यदि ऐसा है तो "दृश्यमान" नियंत्रक लौटें, जो आमतौर पर सबसे कस्टम के लिए vc.childControllers.lastObject होगा। कंटेनर वीसी कार्यान्वयन (मुझे लगता है), लेकिन यह कैसे लागू किया जाता है पर निर्भर करेगा
गड्डू

1
मैंने एक अपडेट किए गए सिंटैक्स को छोड़कर इस उत्तर में उसी दृष्टिकोण के साथ एक उत्तर पोस्ट किया है: यह एक स्विच-केस का उपयोग कर रहा है और स्विफ्ट 3 नामकरण सम्मेलनों का अनुसरण करता है: stackoverflow.com/a/42486823/3451975
Jhhut

43

स्विफ्ट में UIApplication के लिए सरल विस्तार ( UITabBarControlleriPhone में और भी अधिक सुविधा के बारे में परवाह है ) :

extension UIApplication {
    class func topViewController(base: UIViewController? = UIApplication.sharedApplication().keyWindow?.rootViewController) -> UIViewController? {

        if let nav = base as? UINavigationController {
            return topViewController(base: nav.visibleViewController)
        }

        if let tab = base as? UITabBarController {
            let moreNavigationController = tab.moreNavigationController

            if let top = moreNavigationController.topViewController where top.view.window != nil {
                return topViewController(top)
            } else if let selected = tab.selectedViewController {
                return topViewController(selected)
            }
        }

        if let presented = base?.presentedViewController {
            return topViewController(base: presented)
        }

        return base
    }
}

सरल उपयोग:

    if let rootViewController = UIApplication.topViewController() {
        //do sth with root view controller
    }

सही काम करता है :-)

स्वच्छ कोड के लिए अद्यतन:

extension UIViewController {
    var top: UIViewController? {
        if let controller = self as? UINavigationController {
            return controller.topViewController?.top
        }
        if let controller = self as? UISplitViewController {
            return controller.viewControllers.last?.top
        }
        if let controller = self as? UITabBarController {
            return controller.selectedViewController?.top
        }
        if let controller = presentedViewController {
            return controller.top
        }
        return self
    }
}

1
यह स्विफ्ट 2.x के लिए कोड प्रतीत होता है। स्विफ्ट 3.x में "अब" नहीं है। इसके अलावा, "shareApplication ()" अब "साझा" है। कोई बड़ी बात नहीं। अपडेट होने में केवल एक मिनट लगता है। यह उल्लेख करना अच्छा होगा कि यह पुनरावर्तन का उपयोग करता है। इसके अलावा, topViewController के लिए प्रत्येक कॉल को "आधार:" उपसर्ग की आवश्यकता होनी चाहिए।
जेफ मुइर

37

आप NSNotificationCenter के माध्यम से एक अधिसूचना भी पोस्ट कर सकते हैं। आइए, आप कई स्थितियों से निपटते हैं जहां दृश्य नियंत्रक पदानुक्रम का पता लगाना मुश्किल हो सकता है - उदाहरण के लिए जब मॉडल्स प्रस्तुत किए जा रहे हैं, आदि।

उदाहरण के लिए,

// MyAppDelegate.h
NSString * const UIApplicationDidReceiveRemoteNotification;

// MyAppDelegate.m
NSString * const UIApplicationDidReceiveRemoteNotification = @"UIApplicationDidReceiveRemoteNotification";

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

    [[NSNotificationCenter defaultCenter]
     postNotificationName:UIApplicationDidReceiveRemoteNotification
     object:self
     userInfo:userInfo];
}

आपके प्रत्येक दृश्य नियंत्रक में:

-(void)viewDidLoad {
    [[NSNotificationCenter defaultCenter] 
      addObserver:self
      selector:@selector(didReceiveRemoteNotification:)                                                  
      name:UIApplicationDidReceiveRemoteNotification
      object:nil];
}

-(void)viewDidUnload {
    [[NSNotificationCenter defaultCenter] 
      removeObserver:self
      name:UIApplicationDidReceiveRemoteNotification
      object:nil];
}

-(void)didReceiveRemoteNotification:(NSDictionary *)userInfo {
    // see http://stackoverflow.com/a/2777460/305149
   if (self.isViewLoaded && self.view.window) {
      // handle the notification
   }
}

आप इस दृष्टिकोण का उपयोग साधन नियंत्रणों के लिए भी कर सकते हैं जो एक अधिसूचना प्राप्त होने पर अद्यतन करने की आवश्यकता होती है और कई दृश्य नियंत्रकों द्वारा उपयोग की जाती है। उस स्थिति में, क्रमशः इनिट और डीललॉक विधियों में पर्यवेक्षक कॉल को जोड़ें / हटाएं।


1
addObserver:barअंदर क्या है viewDidLoad? क्या मुझे साथ बदलना होगा self?
कैनसौज़ा

यह इंगित करने के लिए धन्यवाद कि यह स्वयं होना चाहिए। मैं जवाब अपडेट कर दूंगा।
अनिल मल्लावरपु

userInfo से सभी कुंजी प्राप्त करते समय दुर्घटना .. कोई विचार? [NSConcreteNotification allKeys]: गैर-मान्यताप्राप्त चयनकर्ता को उदाहरण के लिए भेजा गया है 0x1fd87480 2013-07-05 16: 10: 36.469 प्रोविज़न [2961: 907] *** अपवादित अपवाद के कारण एप्लिकेशन समाप्त करना 'NSInvalidArgumentException', कारण: '- [NSConcretcrete] चयनकर्ता को उदाहरण 0x1fd87480 पर भेजा गया
Awais तारिक

@AwaisTariq - Hmmm - मेरा अनुमान है कि iOS के द्वारा doReceiveRemoteNotification को पास किया गया ऑब्जेक्ट वास्तव में एक एनएस छाया नहीं है, जैसा कि इंटरफ़ेस निर्दिष्ट करता है।
अनिल मल्लावरापु

अगर आपके पर्यवेक्षक वर्ग के लिए उपयोगकर्ता ने अभी तक नेविगेट नहीं किया है तो क्या होगा? : /
हलबानो

15

कोड

यहां स्विफ्ट 3/4/5 में शानदार स्विच-केस सिंटैक्स का उपयोग किया गया है :

extension UIWindow {
    /// Returns the currently visible view controller if any reachable within the window.
    public var visibleViewController: UIViewController? {
        return UIWindow.visibleViewController(from: rootViewController)
    }

    /// Recursively follows navigation controllers, tab bar controllers and modal presented view controllers starting
    /// from the given view controller to find the currently visible view controller.
    ///
    /// - Parameters:
    ///   - viewController: The view controller to start the recursive search from.
    /// - Returns: The view controller that is most probably visible on screen right now.
    public static func visibleViewController(from viewController: UIViewController?) -> UIViewController? {
        switch viewController {
        case let navigationController as UINavigationController:
            return UIWindow.visibleViewController(from: navigationController.visibleViewController ?? navigationController.topViewController)

        case let tabBarController as UITabBarController:
            return UIWindow.visibleViewController(from: tabBarController.selectedViewController)

        case let presentingViewController where viewController?.presentedViewController != nil:
            return UIWindow.visibleViewController(from: presentingViewController?.presentedViewController)

        default:
            return viewController
        }
    }
}

मूल विचार zirinisp के उत्तर के समान है, यह सिंटैक्स की तरह अधिक स्विफ्ट 3+ का उपयोग कर रहा है।


प्रयोग

आप शायद नाम से एक फ़ाइल बनाना चाहते हैं UIWindowExtension.swift। सुनिश्चित करें कि इसमें import UIKitविवरण शामिल है , अब उपरोक्त एक्सटेंशन कोड को कॉपी करें

कॉल पक्ष पर इसका उपयोग या तो किसी विशिष्ट दृश्य नियंत्रक के बिना किया जा सकता है :

if let visibleViewCtrl = UIApplication.shared.keyWindow?.visibleViewController {
    // do whatever you want with your `visibleViewCtrl`
}

या यदि आप जानते हैं कि आपका दृश्य दृश्य नियंत्रक किसी विशिष्ट दृश्य नियंत्रक से उपलब्ध है :

if let visibleViewCtrl = UIWindow.visibleViewController(from: specificViewCtrl) {
    // do whatever you want with your `visibleViewCtrl`
}

मुझे उम्मीद है यह मदद करेगा!


तीसरा मामला एक अनंत पुनरावृत्ति के कारण दुर्घटनाग्रस्त हो जाएगा। फिक्स के रूप में वीसी का नाम बदलना है presentingViewControllerऔर presentingViewController.presentedViewControllerपुनरावर्ती विधि के पैरामीटर के रूप में पास करना है।
इखसन असात

मुझे यह समझ में नहीं आया, क्षमा करें। आपका मतलब UIWindow.visibleViewController(from: presentedViewController)इसके बजाय होना चाहिए UIWindow.visibleViewController(from: presentingViewController.presentedViewController)?
जीहुत

सही बात, presentedViewController और viewControllerएक ही वस्तु है और यह स्टैक ओवरफ्लो (इच्छित उद्देश्य) तक अपने आप से विधि को कॉल करेगा। तो यह होगा case let presentingViewController where viewController?.presentedViewController != nil: return UIWindow.visibleViewController(from: presentingViewController.presentedViewController)
इखसन असाट

1
यह समाधान तब काम किया जब दूसरों ने नहीं किया। आपको स्विफ्ट 5 में अपडेट करना चाहिए। अनिवार्य रूप से कोई बदलाव नहीं। बस अपने उत्तर के लिए हेडर को अपडेट करें।
टीएम लिंच

14

मैंने पाया है कि iOS 8 ने सब कुछ खराब कर दिया है। IOS 7 में UITransitionViewजब भी आप एक मामूली रूप से प्रस्तुत करते हैं, तो पदानुक्रम पर एक नया होता है UINavigationController। वैसे भी, यहाँ मेरा कोड है कि सबसे ऊपर वीसी हो जाता है पाता है। कॉलिंग से getTopMostViewControllerएक वीसी को लौटना चाहिए कि आपको एक संदेश भेजने में सक्षम होना चाहिए presentViewController:animated:completion। यह उद्देश्य है कि आप एक वीसी प्राप्त करें जिसका उपयोग आप एक मोडल वीसी को प्रस्तुत करने के लिए कर सकते हैं, इसलिए यह सबसे अधिक संभावना है कि कंटेनर कक्षाओं में रुकें और वापस लौटें UINavigationControllerऔर न कि वीसी उनके भीतर निहित हो। ऐसा करने के लिए कोड को अनुकूलित करना कठिन नहीं होना चाहिए। मैंने iOS 6, 7 और 8 में विभिन्न स्थितियों में इस कोड का परीक्षण किया है। कृपया मुझे बताएं कि क्या आपको बग मिलते हैं।

+ (UIViewController*) getTopMostViewController
{
    UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    if (window.windowLevel != UIWindowLevelNormal) {
        NSArray *windows = [[UIApplication sharedApplication] windows];
        for(window in windows) {
            if (window.windowLevel == UIWindowLevelNormal) {
                break;
            }
        }
    }

    for (UIView *subView in [window subviews])
    {
        UIResponder *responder = [subView nextResponder];

        //added this block of code for iOS 8 which puts a UITransitionView in between the UIWindow and the UILayoutContainerView
        if ([responder isEqual:window])
        {
            //this is a UITransitionView
            if ([[subView subviews] count])
            {
                UIView *subSubView = [subView subviews][0]; //this should be the UILayoutContainerView
                responder = [subSubView nextResponder];
            }
        }

        if([responder isKindOfClass:[UIViewController class]]) {
            return [self topViewController: (UIViewController *) responder];
        }
    }

    return nil;
}

+ (UIViewController *) topViewController: (UIViewController *) controller
{
    BOOL isPresenting = NO;
    do {
        // this path is called only on iOS 6+, so -presentedViewController is fine here.
        UIViewController *presented = [controller presentedViewController];
        isPresenting = presented != nil;
        if(presented != nil) {
            controller = presented;
        }

    } while (isPresenting);

    return controller;
}

कृपया उत्तरों को डुप्लिकेट न करें - या तो प्रश्नों को ध्वजांकित के रूप में डुप्लिकेट करें यदि वे हैं, या वे विशिष्ट प्रश्नों के साथ व्यक्तिगत प्रश्नों का उत्तर दें जिनके वे डुप्लिकेट नहीं हैं।
फ्लेक्सो

13

अन्य सभी समाधानों की तुलना में कम कोड:

उद्देश्य-सी संस्करण:

- (UIViewController *)getTopViewController {
    UIViewController *topViewController = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
    while (topViewController.presentedViewController) topViewController = topViewController.presentedViewController;

    return topViewController;
}

स्विफ्ट 2.0 संस्करण: (क्रेडिट स्टीव.बी को जाता है)

func getTopViewController() -> UIViewController {
    var topViewController = UIApplication.sharedApplication().delegate!.window!!.rootViewController!
    while (topViewController.presentedViewController != nil) {
        topViewController = topViewController.presentedViewController!
    }
    return topViewController
}

अपने एप्लिकेशन में कहीं भी काम करता है, यहां तक ​​कि मॉडल के साथ भी।


1
यह उस स्थिति को नहीं संभालता है जहां प्रस्तुत दृश्य नियंत्रक एक है UINavigationControllerजिसके अपने बच्चे हैं।
लेविग्रोकर

@levigroker, शायद यह वह तरीका है जिससे आप अपने विचारों को चित्रित कर रहे हैं? यह मेरे लिए एक नव के साथ इस का उपयोग करने के लिए ठीक काम करता है। (यह है कि मैं इसे कैसे इस्तेमाल कर रहा हूं)
jungledev

@jungledev मुझे यकीन है कि आप सही हैं। उस ने कहा, एक समाधान जो सभी व्यू कंट्रोलर कॉन्फ़िगरेशन में काम करता है, उसकी आवश्यकता है।
लेविग्रोकर

@levigroker यह सभी मानक vc कॉन्फ़िगरेशन में काम करता है- जिस ऐप पर मैं काम करता हूं, उसके पास वास्तव में जटिल वास्तुकला है, 500k से अधिक उपयोगकर्ताओं द्वारा उपयोग किया जाता है, और यह ऐप में हर जगह काम करता है। शायद आपको एक सवाल पोस्ट करना चाहिए कि यह कोड के उदाहरणों के साथ आपके विचार में काम क्यों नहीं करता है?
जुंगलेव

jungledev मुझे खुशी है कि यह कोड आपके लिए काम करता है, लेकिन यह पूर्ण समाधान नहीं प्रतीत होता है। @ zirinisp का जवाब मेरी स्थिति में पूरी तरह से काम करता है।
लेविग्रोकर

8

स्विफ्ट में zirinisp का जवाब:

extension UIWindow {

    func visibleViewController() -> UIViewController? {
        if let rootViewController: UIViewController  = self.rootViewController {
            return UIWindow.getVisibleViewControllerFrom(rootViewController)
        }
        return nil
    }

    class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {

        if vc.isKindOfClass(UINavigationController.self) {

            let navigationController = vc as UINavigationController
            return UIWindow.getVisibleViewControllerFrom( navigationController.visibleViewController)

        } else if vc.isKindOfClass(UITabBarController.self) {

            let tabBarController = vc as UITabBarController
            return UIWindow.getVisibleViewControllerFrom(tabBarController.selectedViewController!)

        } else {

            if let presentedViewController = vc.presentedViewController {

                return UIWindow.getVisibleViewControllerFrom(presentedViewController.presentedViewController!)

            } else {

                return vc;
            }
        }
    }
}

उपयोग:

 if let topController = window.visibleViewController() {
            println(topController)
        }

यह है as!और navigationController.visibleViewController!स्विफ्ट 2.0 के लिए
LinusGeffarth 20

7

प्रत्येक ViewController को शीर्षक निर्दिष्ट करें और फिर नीचे दिए गए कोड द्वारा वर्तमान ViewController का शीर्षक प्राप्त करें।

-(void)viewDidUnload {
  NSString *currentController = self.navigationController.visibleViewController.title;

फिर इसे अपने शीर्षक द्वारा इस तरह जांचें

  if([currentController isEqualToString:@"myViewControllerTitle"]){
    //write your code according to View controller.
  }
}

Dfntly सबसे अच्छा जवाब है, यह भी यू अपने ViewController साथ नाम कर सकते हैं:self.title = myPhotoView
Resty

5

मेरा बेहतर है! :)

extension UIApplication {
    var visibleViewController : UIViewController? {
        return keyWindow?.rootViewController?.topViewController
    }
}

extension UIViewController {
    fileprivate var topViewController: UIViewController {
        switch self {
        case is UINavigationController:
            return (self as! UINavigationController).visibleViewController?.topViewController ?? self
        case is UITabBarController:
            return (self as! UITabBarController).selectedViewController?.topViewController ?? self
        default:
            return presentedViewController?.topViewController ?? self
        }
    }
}

4

ऐप डेलिगेट में सिर्फ पुश नोटिफिकेशन कोड को ही क्यों न हैंडल किया जाए? क्या यह प्रत्यक्ष रूप से एक दृश्य से संबंधित है?

आप देख सकते हैं कि क्या UIViewController का दृश्य वर्तमान में चेक करके दिखाई दे रहा है कि यह दृश्य की windowसंपत्ति का मान है या नहीं। अधिक देखें यहाँ


हां, यह एक दृश्य से संबंधित है, क्योंकि मुझे बैज दृश्य दिखाना है। मुझे लिंक की जाँच करने दें। धन्यवाद :)
लू युआन

4

सिर्फ @zirinisp जवाब के अलावा।

एक फ़ाइल बनाएं, इसे नाम दें UIWindowExtension.swiftऔर निम्नलिखित स्निपेट पेस्ट करें:

import UIKit

public extension UIWindow {
    public var visibleViewController: UIViewController? {
        return UIWindow.getVisibleViewControllerFrom(self.rootViewController)
    }

    public static func getVisibleViewControllerFrom(vc: UIViewController?) -> UIViewController? {
        if let nc = vc as? UINavigationController {
            return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController)
        } else if let tc = vc as? UITabBarController {
            return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController)
        } else {
            if let pvc = vc?.presentedViewController {
                return UIWindow.getVisibleViewControllerFrom(pvc)
            } else {
                return vc
            }
        }
    }
}

func getTopViewController() -> UIViewController? {
    let appDelegate = UIApplication.sharedApplication().delegate
    if let window = appDelegate!.window {
        return window?.visibleViewController
    }
    return nil
}

इसे कहीं भी उपयोग करें:

if let topVC = getTopViewController() {

}

@Zirinisp को धन्यवाद।


3

ऊपर NSNotificationCenter पोस्ट के बारे में (क्षमा करें पता नहीं कर सकते हैं, जहां इसके तहत एक टिप्पणी पोस्ट करने के लिए ...)

मामले में कुछ मिल रहे थे - [NSConcreteNotification allKeys] प्रकार की त्रुटि। इसे बदलो:

-(void)didReceiveRemoteNotification:(NSDictionary *)userInfo

इसके लिए:

-(void)didReceiveRemoteNotification:(NSNotification*)notif {
NSDictionary *dict = notif.userInfo;
}

3

इसने मेरे लिए काम किया। मेरे पास कई लक्ष्य हैं जिनके अलग-अलग नियंत्रक हैं इसलिए पिछले उत्तर काम नहीं करते थे।

पहले आप अपने AppDelegate वर्ग के अंदर यह चाहते हैं:

var window: UIWindow?

फिर, अपने फ़ंक्शन में

let navigationController = window?.rootViewController as? UINavigationController
if let activeController = navigationController!.visibleViewController {
    if activeController.isKindOfClass( MyViewController )  {
        println("I have found my controller!")    
   }
}

2

यह सबसे अच्छा संभव तरीका है जिसे मैंने आजमाया है। अगर यह किसी की मदद करनी चाहिए ...

+ (UIViewController*) topMostController
{
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

    while (topController.presentedViewController) {
        topController = topController.presentedViewController;
    }

    return topController;
}

2
extension UIApplication {
    /// The top most view controller
    static var topMostViewController: UIViewController? {
        return UIApplication.shared.keyWindow?.rootViewController?.visibleViewController
    }
}

extension UIViewController {
    /// The visible view controller from a given view controller
    var visibleViewController: UIViewController? {
        if let navigationController = self as? UINavigationController {
            return navigationController.topViewController?.visibleViewController
        } else if let tabBarController = self as? UITabBarController {
            return tabBarController.selectedViewController?.visibleViewController
        } else if let presentedViewController = presentedViewController {
            return presentedViewController.visibleViewController
        } else {
            return self
        }
    }
}

इससे आप आसानी से टॉप पोस्ट व्यू कंट्रोलर प्राप्त कर सकते हैं

let viewController = UIApplication.topMostViewController

एक बात का ध्यान रखें कि यदि वर्तमान में एक UIAlertController प्रदर्शित हो रही है, तो UIApplication.topMostViewControllerवह वापस आ जाएगी UIAlertController


1

जंगलेवेद के जवाब का 2.0 संस्करण

func getTopViewController() -> UIViewController {
    var topViewController = UIApplication.sharedApplication().delegate!.window!!.rootViewController!
    while (topViewController.presentedViewController != nil) {
        topViewController = topViewController.presentedViewController!
    }
    return topViewController
}

1

मैं के लिए एक श्रेणी बनाई UIApplicationके साथ visibleViewControllersसंपत्ति। मुख्य विचार बहुत सरल है। मैं झेंप गया viewDidAppearऔर viewDidDisappearतरीकों में UIViewController। में viewDidAppearविधि ViewController ढेर में जोड़ा जाता है। में viewDidDisappearविधि ViewController ढेर से निकाल दिया जाता। कमजोर संदर्भों को संग्रहीत करने के NSPointerArrayबजाय उपयोग किया जाता है । यह दृष्टिकोण किसी भी दृश्य नियंत्रक के लिए काम करता है।NSArrayUIViewController

UIApplication + VisibleViewControllers.h

#import <UIKit/UIKit.h>

@interface UIApplication (VisibleViewControllers)

@property (nonatomic, readonly) NSArray<__kindof UIViewController *> *visibleViewControllers;

@end

UIApplication + VisibleViewControllers.m

#import "UIApplication+VisibleViewControllers.h"
#import <objc/runtime.h>

@interface UIApplication ()

@property (nonatomic, readonly) NSPointerArray *visibleViewControllersPointers;

@end

@implementation UIApplication (VisibleViewControllers)

- (NSArray<__kindof UIViewController *> *)visibleViewControllers {
    return self.visibleViewControllersPointers.allObjects;
}

- (NSPointerArray *)visibleViewControllersPointers {
    NSPointerArray *pointers = objc_getAssociatedObject(self, @selector(visibleViewControllersPointers));
    if (!pointers) {
        pointers = [NSPointerArray weakObjectsPointerArray];
        objc_setAssociatedObject(self, @selector(visibleViewControllersPointers), pointers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return pointers;
}

@end

@implementation UIViewController (UIApplication_VisibleViewControllers)

+ (void)swizzleMethodWithOriginalSelector:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
    BOOL didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {
        class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self swizzleMethodWithOriginalSelector:@selector(viewDidAppear:)
                               swizzledSelector:@selector(uiapplication_visibleviewcontrollers_viewDidAppear:)];
        [self swizzleMethodWithOriginalSelector:@selector(viewDidDisappear:)
                               swizzledSelector:@selector(uiapplication_visibleviewcontrollers_viewDidDisappear:)];
    });
}

- (void)uiapplication_visibleviewcontrollers_viewDidAppear:(BOOL)animated {
    [[UIApplication sharedApplication].visibleViewControllersPointers addPointer:(__bridge void * _Nullable)self];
    [self uiapplication_visibleviewcontrollers_viewDidAppear:animated];
}

- (void)uiapplication_visibleviewcontrollers_viewDidDisappear:(BOOL)animated {
    NSPointerArray *pointers = [UIApplication sharedApplication].visibleViewControllersPointers;
    for (int i = 0; i < pointers.count; i++) {
        UIViewController *viewController = [pointers pointerAtIndex:i];
        if ([viewController isEqual:self]) {
            [pointers removePointerAtIndex:i];
            break;
        }
    }
    [self uiapplication_visibleviewcontrollers_viewDidDisappear:animated];
}

@end

https://gist.github.com/medvedzzz/e6287b99011f2437ac0beb5a72a897f0

स्विफ्ट 3 संस्करण

UIApplication + VisibleViewControllers.swift

import UIKit

extension UIApplication {

    private struct AssociatedObjectsKeys {
        static var visibleViewControllersPointers = "UIApplication_visibleViewControllersPointers"
    }

    fileprivate var visibleViewControllersPointers: NSPointerArray {
        var pointers = objc_getAssociatedObject(self, &AssociatedObjectsKeys.visibleViewControllersPointers) as! NSPointerArray?
        if (pointers == nil) {
            pointers = NSPointerArray.weakObjects()
            objc_setAssociatedObject(self, &AssociatedObjectsKeys.visibleViewControllersPointers, pointers, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        return pointers!
    }

    var visibleViewControllers: [UIViewController] {
        return visibleViewControllersPointers.allObjects as! [UIViewController]
    }
}

extension UIViewController {

    private static func swizzleFunc(withOriginalSelector originalSelector: Selector, swizzledSelector: Selector) {
        let originalMethod = class_getInstanceMethod(self, originalSelector)
        let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
        let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
        if didAddMethod {
            class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }

    override open class func initialize() {
        if self != UIViewController.self {
            return
        }
        let swizzlingClosure: () = {
            UIViewController.swizzleFunc(withOriginalSelector: #selector(UIViewController.viewDidAppear(_:)),
                                         swizzledSelector: #selector(uiapplication_visibleviewcontrollers_viewDidAppear(_:)))
            UIViewController.swizzleFunc(withOriginalSelector: #selector(UIViewController.viewDidDisappear(_:)),
                                         swizzledSelector: #selector(uiapplication_visibleviewcontrollers_viewDidDisappear(_:)))
        }()
        swizzlingClosure
    }

    @objc private func uiapplication_visibleviewcontrollers_viewDidAppear(_ animated: Bool) {
        UIApplication.shared.visibleViewControllersPointers.addPointer(Unmanaged.passUnretained(self).toOpaque())
        uiapplication_visibleviewcontrollers_viewDidAppear(animated)
    }

    @objc private func uiapplication_visibleviewcontrollers_viewDidDisappear(_ animated: Bool) {
        let pointers = UIApplication.shared.visibleViewControllersPointers
        for i in 0..<pointers.count {
            if let pointer = pointers.pointer(at: i) {
                let viewController = Unmanaged<AnyObject>.fromOpaque(pointer).takeUnretainedValue() as? UIViewController
                if viewController.isEqual(self) {
                    pointers.removePointer(at: i)
                    break
                }
            }
        }
        uiapplication_visibleviewcontrollers_viewDidDisappear(animated)
    }
}

https://gist.github.com/medvedzzz/ee6f4071639d987793977dba04e11399


1

यदि आप अपने ऐप को डिबग या रिलीज़ के साथ चला रहे हैं, तो हमेशा अपने बिल्ड कॉन्फ़िगरेशन की जांच करें।

महत्वपूर्ण नोट: आप डिबग मोड में अपना ऐप चलाए बिना इसका परीक्षण नहीं कर सकते

यह मेरा समाधान था

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