viewWillDisappear: निर्धारित करें कि क्या व्यू कंट्रोलर पॉप-अप हो रहा है या सब-व्यू कंट्रोलर दिखा रहा है


134

मैं इस समस्या का एक अच्छा समाधान खोजने के लिए संघर्ष कर रहा हूँ। एक दृश्य नियंत्रक -viewWillDisappear:विधि में, मुझे यह निर्धारित करने के लिए एक तरीका खोजने की आवश्यकता है कि क्या यह है क्योंकि एक दृश्य नियंत्रक को नेविगेशन नियंत्रक के ढेर पर धकेल दिया जा रहा है, या क्या यह इसलिए है क्योंकि दृश्य नियंत्रक गायब हो रहा है क्योंकि यह पॉप हो गया है।

फिलहाल मैं झंडे स्थापित कर रहा हूं जैसे कि isShowingChildViewControllerयह काफी जटिल है। एकमात्र तरीका मुझे लगता है कि मैं इसका पता लगा सकता हूं कि यह -deallocविधि में है।

जवाबों:


228

आप निम्नलिखित का उपयोग कर सकते हैं।

- (void)viewWillDisappear:(BOOL)animated {
  [super viewWillDisappear:animated];
  NSArray *viewControllers = self.navigationController.viewControllers;
  if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
    // View is disappearing because a new view controller was pushed onto the stack
    NSLog(@"New view controller was pushed");
  } else if ([viewControllers indexOfObject:self] == NSNotFound) {
    // View is disappearing because it was popped from the stack
    NSLog(@"View controller was popped");
  }
}

यह निश्चित रूप से संभव है, क्योंकि UINavigationController के व्यू कंट्रोलर स्टैक (viewControllers प्रॉपर्टी के माध्यम से उजागर) को उस समय तक अपडेट कर दिया गया है जब viewWillDisappear कहा जाता है।


2
उत्तम! मुझे नहीं पता कि मैंने ऐसा क्यों नहीं सोचा! मुझे लगता है कि मुझे नहीं लगता था कि स्टैक को तब तक बदल दिया जाएगा जब तक कि गायब तरीकों को नहीं बुलाया गया था! धन्यवाद :-)
माइकल झरना 21

1
मैं बस एक ही चीज़ करने की कोशिश कर रहा हूं, लेकिन viewWillAppearऐसा लगता है कि दृश्य नियंत्रक द्वारा इसे धकेला जा रहा है या इसके ऊपर कुछ दिखाई दे रहा है या नहीं, व्यूकोन्ट्रोलर्स एरे दोनों ही तरीके हैं! कोई विचार?
माइकल झरना

मुझे यह भी ध्यान रखना चाहिए कि दृश्य नियंत्रक ऐप के जीवनकाल के माध्यम से लगातार बना रहता है, इसलिए मैं अपने कार्यों को निष्पादित नहीं कर सकता viewDidLoadक्योंकि यह केवल एक बार कहा जाता है! हम्म, मुश्किल एक!
माइकल वाटरफॉल

4
@Sbrocket एक कारण है जिसके ![viewControllers containsObject:self]बजाय आपने ऐसा नहीं किया [viewControllers indexOfObject:self] == NSNotFound? शैली पसंद है?
zekel

24
IOS 5 के बाद से यह उत्तर अप्रचलित है। -isMovingFromParentViewControllerनीचे दी गई विधि आपको यह परखने की अनुमति देती है कि क्या दृश्य स्पष्ट रूप से पॉप किया जा रहा है।
ग्रहमपार्क

136

मुझे लगता है कि सबसे आसान तरीका है:

 - (void)viewWillDisappear:(BOOL)animated
{
    if ([self isMovingFromParentViewController])
    {
        NSLog(@"View controller was popped");
    }
    else
    {
        NSLog(@"New view controller was pushed");
    }
    [super viewWillDisappear:animated];
}

स्विफ्ट:

override func viewWillDisappear(animated: Bool)
{
    if isMovingFromParent
    {
        print("View controller was popped")
    }
    else
    {
        print("New view controller was pushed")
    }
    super.viewWillDisappear(animated)
}

IOS 5 के रूप में इस सवाल का जवाब है, हो सकता है यह भी isBeingDismissed जाँच
d370urn3ur

4
IOS7 के लिए मुझे [self.navigationController.viewControllers indexOfObject: self] == NSNotFound को फिर से जांचना होगा क्योंकि ऐप को बैकग्राउंड करने से यह टेस्ट भी पास हो जाएगा लेकिन नेविगेशन स्टैक से सेल्फ नहीं हटाएगा।
एरिक चेन

3
Apple ने ऐसा करने के लिए एक प्रलेखित तरीका प्रदान किया है - stackoverflow.com/a/33478133/385708
श्याम भट्ट

ViewWillDisappear का उपयोग करने में समस्या यह है कि यह संभव है कि कंट्रोलर स्टैक से पॉपअप हो, जबकि दृश्य पहले ही गायब हो गया हो। उदाहरण के लिए, स्टैक के शीर्ष पर एक और व्यूकंट्रोलर को धकेला जा सकता है और फिर popToRootViewControllerAnimated को देखते हुए बायपास किया जा सकता है।
जॉन के

मान लीजिए कि आपके नेविगेशन स्टैक पर आपके पास दो नियंत्रक (रूट वीसी और एक और धक्का दिया गया) है। जब तीसरे को धक्का दिया जा रहा हो तो दूसरे नंबर पर विलीडिसपियर को बुलाया जाता है जिसका दृश्य गायब होने वाला है, है ना? इसलिए जब आप व्यू कंट्रोलर को रूट करते हैं (तीसरे और दूसरे को पॉप करते हैं) व्यू डिलिसैपियर को स्टैक पर तीसरे यानी आखिरी vc पर कॉल किया जाता है क्योंकि यह दृश्य शीर्ष पर है और इस समय गायब होने वाला है और दूसरे का दृश्य पहले ही गायब हो गया था। इसीलिए इस तरीके को viewWillDisappear कहा जाता है न कि viewControllerWillBePontin।
RTasche

61

UIViewController.h में Apple के प्रलेखन से:

"इन चार विधियों का उपयोग एक दृश्य नियंत्रक की उपस्थिति कॉलबैक में यह निर्धारित करने के लिए किया जा सकता है कि क्या इसे प्रस्तुत किया जा रहा है, खारिज किया गया है, या जोड़ा गया है या एक चाइल्ड व्यू कंट्रोलर के रूप में हटा दिया गया है। उदाहरण के लिए, एक दृश्य नियंत्रक यह देख सकता है कि क्या यह गायब हो रहा है क्योंकि इसे खारिज कर दिया गया था या। अपने दृष्टिकोण में खुद को पूछकर पॉपअप किया गया है: अभिव्यक्ति की जाँच करके विधि: ([स्वयं isBeingDisississed] की जाँच करके।

- (BOOL)isBeingPresented NS_AVAILABLE_IOS(5_0);

- (BOOL)isBeingDismissed NS_AVAILABLE_IOS(5_0);

- (BOOL)isMovingToParentViewController NS_AVAILABLE_IOS(5_0);

- (BOOL)isMovingFromParentViewController NS_AVAILABLE_IOS(5_0);

तो हाँ, ऐसा करने का एकमात्र प्रलेखित तरीका निम्नलिखित है:

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    if ([self isBeingDismissed] || [self isMovingFromParentViewController]) {
    }
}

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

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    
    if self.isBeingDismissed || self.isMovingFromParentViewController { 
    }
}

18

आप सिर्फ इतना पता करने के लिए अपने दृश्य पॉपअप हो रही है कि क्या चाहते हैं, मैं तो बस पता चला कि self.navigationControllerहै nilमें viewDidDisappear, जब यह नियंत्रकों के ढेर से निकाल दिया जाता। तो यह एक सरल वैकल्पिक परीक्षण है।

(यह सभी अन्य प्रकार के गर्भपात की कोशिश करने के बाद पता चलता है। मुझे आश्चर्य है कि पॉप पर होने के लिए व्यू कंट्रोलर रजिस्टर करने के लिए कोई नेविगेशन नियंत्रक प्रोटोकॉल नहीं है। आप इसका उपयोग नहीं कर सकते UINavigationControllerDelegateक्योंकि यह वास्तव में वास्तविक प्रदर्शन कार्य करता है।)


16

स्विफ्ट 4

override func viewWillDisappear(_ animated: Bool)
    {
        super.viewWillDisappear(animated)
        if self.isMovingFromParent
        {
            //View Controller Popped
        }
        else
        {
            //New view controller pushed
        }
    }

6

स्विफ्ट में:

 override func viewWillDisappear(animated: Bool) {
    if let navigationController = self.navigationController {
        if !contains(navigationController.viewControllers as! Array<UIViewController>, self) {
        }
    }

    super.viewWillDisappear(animated)

}

के रूप में उपयोग करने के लिए सुनिश्चित करें! इसके बजाय
dfmuir

2

मुझे लगता है कि इस पर Apple के प्रलेखन को समझना मुश्किल है। यह एक्सटेंशन राज्यों को प्रत्येक नेविगेशन पर देखने में मदद करता है।

extension UIViewController {
    public func printTransitionStates() {
        print("isBeingPresented=\(isBeingPresented)")
        print("isBeingDismissed=\(isBeingDismissed)")
        print("isMovingToParentViewController=\(isMovingToParentViewController)")
        print("isMovingFromParentViewController=\(isMovingFromParentViewController)")
    }
}

1

यह प्रश्न काफी पुराना है लेकिन मैंने इसे दुर्घटना से देखा इसलिए मैं सबसे अच्छा अभ्यास (afaik) पोस्ट करना चाहता हूं

आप बस कर सकते हैं

if([self.navigationController.viewControllers indexOfObject:self]==NSNotFound)
 // view controller popped
}

1

यह iOS7 पर लागू होता है , अगर यह किसी भी अन्य पर लागू होता है तो कोई विचार नहीं है। जो मुझे पता है, उससे viewDidDisappearपहले से ही पॉपप हो चुका है। जिसका मतलब है जब आप क्वेरी self.navigationController.viewControllersकरेंगे तो आपको एकnil । तो बस जाँच करें कि क्या शून्य है।

टी एल; डॉ

 - (void)viewDidDisappear:(BOOL)animated
 {
    [super viewDidDisappear:animated];
    if (self.navigationController.viewControllers == nil) {
        // It has been popped!
        NSLog(@"Popped and Gone");
    }
 }

1

IOS 6+ में इस समस्या से निपटने के लिए सेगमेंट एक बहुत प्रभावी तरीका हो सकता है। यदि आपने विशेष रूप से सेगमेंट को इंटरफ़ेस बिल्डर में दिया है, तो आप इसके लिए जांच कर सकते हैं prepareForSegue

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"LoginSegue"]) {
       NSLog(@"Push");
       // Do something specific here, or set a BOOL indicating
       // a push has occurred that will be checked later
    }
}

1

धन्यवाद @ ब्रायन हेनरी, फिर भी स्विफ्ट 5 में काम करता है

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if let controllers = navigationController?.children{
            if controllers.count > 1, controllers[controllers.count - 2] == self{
                // View is disappearing because a new view controller was pushed onto the stack
                print("New view controller was pushed")
            }
            else if controllers.firstIndex(of: self) == nil{
                // View is disappearing because it was popped from the stack
                print("View controller was popped")
            }
        }

    }

-1

मेरा मानना ​​है कि जब आप कहते हैं कि स्टैक पर धकेल दिया गया है, तो एक नए दृश्य को धक्का देकर आपका दृश्य नेविगेशन नियंत्रक के ढेर के नीचे ले जाया जा रहा है। मैं का उपयोग कर सुझाव है कि viewDidUnloadएक जोड़ने के लिए विधि NSLogकंसोल के लिए कुछ लिखने के लिए बयान इसलिए आप देख सकते क्या चल रहा है, तो आप एक जोड़ सकते हैं NSLogकरने के लिए viewWillDissappeer


-1

यहाँ एक ही चीज़ को पूरा करने के लिए एक श्रेणी दी गई है जो कि sbrocket का उत्तर है:

हैडर:

#import <UIKit/UIKit.h>

@interface UIViewController (isBeingPopped)

- (BOOL) isBeingPopped;

@end

स्रोत:

#import "UIViewController+isBeingPopped.h"

@implementation UIViewController (isBeingPopped)

- (BOOL) isBeingPopped {
    NSArray *viewControllers = self.navigationController.viewControllers;
    if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
        return NO;
    } else if ([viewControllers indexOfObject:self] == NSNotFound) {
        return YES;
    }
    return NO;
}

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