पता लगाएँ कि प्रस्तुत दृश्य नियंत्रक कब खारिज किया जाता है


82

मान लीजिए, मेरे पास वीसी 2 नामक एक दृश्य नियंत्रक वर्ग का एक उदाहरण है। VC2 में, "रद्द" बटन है जो खुद को खारिज कर देगा। लेकिन जब "रद्द" बटन को ट्रिगर मिल गया तो मैं किसी कॉलबैक का पता नहीं लगा सकता या प्राप्त नहीं कर सकता। VC2 एक ब्लैक बॉक्स है।

एक दृश्य नियंत्रक (जिसे वीसी 1 कहा जाता है) presentViewController:animated:completion:विधि का उपयोग करके वीसी 2 पेश करेगा ।

जब VC2 बर्खास्त कर दिया गया तो VC1 के पास क्या विकल्प हैं?

संपादित करें: @rory mckinnel की टिप्पणी और @NicolasMiari के उत्तर से, मैंने निम्नलिखित कोशिश की:

VC2 में:

-(void)cancelButton:(id)sender
{
    [self dismissViewControllerAnimated:YES completion:^{

    }];
//    [super dismissViewControllerAnimated:YES completion:^{
//        
//    }];
}

VC1 में:

//-(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
- (void)dismissViewControllerAnimated:(BOOL)flag
                           completion:(void (^ _Nullable)(void))completion
{
    NSLog(@"%s ", __PRETTY_FUNCTION__);
    [super dismissViewControllerAnimated:flag completion:completion];
//    [self dismissViewControllerAnimated:YES completion:^{
//        
//    }];
}

लेकिन dismissViewControllerAnimatedवीसी 1 में फोन नहीं हो रहा था।


2
VC1 में viewWillAppear विधि को बुलाया जाएगा
इस्तवन

1
डॉक्स के अनुसार, वर्तमान नियंत्रक वास्तविक बर्खास्तगी के लिए जिम्मेदार है। जब प्रस्तुत नियंत्रक खुद को खारिज कर देता है, तो यह प्रस्तुतकर्ता को इसके लिए करने के लिए कहेगा। इसलिए यदि आप dismissViewControllerAnimatedअपने वीसी 1 नियंत्रक में ओवरराइड करते हैं , तो मेरा मानना ​​है कि जब आप वीसी 2 को रद्द करते हैं तो इसे कॉल किया जाएगा। बर्खास्तगी का पता लगाएं और फिर सुपर क्लास संस्करण को कॉल करें जो वास्तविक खारिज करेगा।
रोरी मैककिनल

1
आप कॉल करके अपने ओवरराइड का परीक्षण कर सकते हैं [self.presentingViewController dismissViewControllerAnimated]। यह हो सकता है कि आंतरिक कोड में प्रस्तुतकर्ता को खारिज करने के लिए कहने के लिए एक अलग तंत्र हो।
रोरी मैकिनल

@RoryMcKinnel: self.pretingViewController का उपयोग करते हुए मेरी लैब VC2 के साथ-साथ वास्तविक ब्लैक बॉक्स से भी काम किया। यदि आप जवाब में अपनी टिप्पणी देते हैं तो मैं इसे उत्तर के रूप में चुनूंगा। धन्यवाद।
user523234

इसके लिए एक समाधान इस संबंधित पोस्ट में पाया जा सकता है: stackoverflow.com/a/34571641/3643020
कैम्पबेल_

जवाबों:


64

डॉक्स के अनुसार, वर्तमान नियंत्रक वास्तविक बर्खास्तगी के लिए जिम्मेदार है। जब प्रस्तुत नियंत्रक खुद को खारिज कर देता है, तो यह प्रस्तुतकर्ता को इसके लिए करने के लिए कहेगा। इसलिए यदि आप अपने वीसी 1 कंट्रोलर में खारिज किए गए व्यूवॉन्ट्रोलर को ओवरराइड करते हैं तो मेरा मानना ​​है कि जब आप वीसी 2 को रद्द करेंगे तो इसे कॉल किया जाएगा। बर्खास्तगी का पता लगाएं और फिर सुपर क्लास संस्करण को कॉल करें जो वास्तविक खारिज करेगा।

जैसा कि चर्चा से पाया गया है कि यह काम नहीं करता है। अंतर्निहित तंत्र पर भरोसा करने के बजाय, dismissViewControllerAnimated:completionVC2 पर कॉल करने के बजाय, VC2 dismissViewControllerAnimated:completionपर कॉल करें self.presentingViewController। यह तब आपके ओवरराइड को सीधे कॉल करेगा।

कुल मिलाकर एक बेहतर तरीका होगा कि VC2 एक ब्लॉक प्रदान करे, जिसे तब कहा जाता है जब मोडल कंट्रोलर पूरा कर लेता है।

तो VC2 में, नाम के साथ एक ब्लॉक संपत्ति कहें onDoneBlock

VC1 में आप निम्नानुसार प्रस्तुत करते हैं:

  • VC1 में, VC2 बनाएँ

  • VC2 के लिए किए गए हैंडलर को निम्नानुसार सेट करें: VC2.onDoneBlock={[VC2 dismissViewControllerAnimated:YES completion:nil]};

  • VC2 नियंत्रक को सामान्य के रूप में प्रस्तुत करें [self presentViewController: VC2 एनिमेटेड: YES पूर्ण: nil];

  • VC2 में, टारगेट एक्शन कॉल को रद्द करें self.onDoneBlock();

परिणाम VC2 बताता है कि जो कोई भी इसे उठाता है कि यह किया जाता है। आप onDoneBlockऐसे तर्क प्रस्तुत कर सकते हैं जो इंगित करते हैं कि क्या मोडल कमिटेड, रद्द, सफल आदि हैं।


2
बस धन्यवाद और सराहना करना चाहता हूं कि यह कितनी खूबसूरती से काम करता है..यहां 4yrs के बाद! धन्यवाद!
अन्ना

48

अंदर एक विशेष बूलियन संपत्ति है UIViewControllerजिसे isBeingDismissedआप इस उद्देश्य के लिए उपयोग कर सकते हैं:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    if isBeingDismissed {
        // TODO: Do your stuff here.
    }
}

3
सबसे आसान उत्तर, अधिकांश समस्याओं को सही ढंग से संबोधित करता है और अतिरिक्त कार्यान्वयन की आवश्यकता नहीं है।
30'19

इसके साथ युग्मित किए बिना यह सही ढंग से काम नहीं करता है viewDidAppear
दिमित्री

9
एक iOS13 मोडल प्रस्तुति में यह सच होगा जब कोई उपयोगकर्ता नियंत्रक को खारिज करने के लिए खींचना शुरू करता है, लेकिन वे बर्खास्तगी को पूरा नहीं करने का विकल्प चुन सकते हैं।
एस्टेल

44

एक ब्लॉक संपत्ति का उपयोग करें

VC2 में घोषणा

var onDoneBlock : ((Bool) -> Void)?

VC1 में सेटअप

VC2.onDoneBlock = { result in
                // Do something
            }

VC2 में कॉल करें जब आप खारिज करने वाले हों

onDoneBlock!(true)

, बिंदु जहां कोड onDoneBlock को जाता है पर (सही) @ Bryce64 यह मेरे लिए काम नहीं कर रहा, मुझे मिल गया "अनपेक्षित रूप से पाया नहीं के बराबर है जबकि एक वैकल्पिक मूल्य unwrapping थ्रेड 1: गंभीर त्रुटि"!
लुकास

@ लुकास लगता है जैसे आपने इसे वीसी 1 में सही ढंग से घोषित नहीं किया। "!" यदि आप इसे सही तरीके से सेट नहीं करते हैं, तो आपको त्रुटि को लागू करने के लिए अनट्रैप को मजबूर करता है।
brycejl

1
केवल एक दृश्य नियंत्रक प्रस्तुत किया जा रहा है। तुम एक नेविगेशन पर हो सकता है ढेर भगवान जानता है कि कहाँ।
ली प्रोबर्ट

@ लिप्रोबर्ट बिल्कुल। हमारे पास लगभग 10 संभावित बाल नियंत्रकों के साथ इसके स्टैक के साथ एक नेविगेशन नियंत्रक है, और उनमें से लगभग हर एक बर्खास्तगी को ट्रिगर कर सकता है ... इस स्थिति में किसी भी पूर्ण ब्लॉक को सभी 10 ऐसे नियंत्रकों को पारित करना होगा
इगोर वासीलेव

13

प्रस्तुत और प्रस्तुत दोनों दृश्य नियंत्रक प्रस्तुत दृश्य नियंत्रक dismissViewController:animated:को खारिज करने के लिए कॉल कर सकते हैं ।

पूर्व विकल्प है (यकीनन) "सही" एक, डिजाइन-वार: एक ही "माता-पिता" व्यू कंट्रोलर दोनों मोडल ("बच्चा") व्यू कंट्रोलर को प्रस्तुत करने और खारिज करने के लिए जिम्मेदार है।

हालाँकि, उत्तरार्द्ध अधिक सुविधाजनक है: आम तौर पर, "खारिज" बटन प्रस्तुत दृश्य नियंत्रक के दृश्य से जुड़ा होता है, और इसने कहा है कि दृश्य नियंत्रक इसके क्रिया लक्ष्य के रूप में सेट है।

यदि आप पूर्व दृष्टिकोण को अपना रहे हैं, तो आप पहले से ही अपने वर्तमान व्यू कंट्रोलर में कोड की लाइन को जानते हैं, जहां बर्खास्तगी होती है: या तो अपना कोड केवल dismissViewControllerAnimated:completion:या उसके बाद पूर्ण ब्लॉक के भीतर चलाएं ।

यदि आप बाद वाला तरीका अपना रहे हैं (प्रस्तुत व्यू कंट्रोलर खुद ही खारिज हो जाता है), तो ध्यान रखें कि dismissViewControllerAnimated:completion:प्रस्तुत व्यू कंट्रोलर से कॉल करने से UIKit को कॉल करने का तरीका पेश करने वाले व्यू कंट्रोलर पर आता है:

विचार-विमर्श

प्रस्तुत दृश्य नियंत्रक उस दृश्य नियंत्रक को खारिज करने के लिए जिम्मेदार है जिसे उसने प्रस्तुत किया है। यदि आप इस विधि को प्रस्तुत किए गए दृश्य नियंत्रक पर कहते हैं, तो UIKit प्रस्तुतकर्ता नियंत्रक को बर्खास्तगी को संभालने के लिए कहता है।

( स्रोत: UIViewController क्लास संदर्भ )

तो, इस तरह की घटना को रोकने के लिए, आप उस विधि को प्रस्तुत करने वाले दृश्य नियंत्रक में ओवरराइड कर सकते हैं :

override func dismiss(animated flag: Bool,
                         completion: (() -> Void)?) {
    super.dismiss(animated: flag, completion: completion)

    // Your custom code here...
}

1
कोई दिक्कत नहीं है। लेकिन यह उम्मीद के मुताबिक काम नहीं करता है। शुक्र है, @ RoryMcKinnel का जवाब अधिक विकल्प देता प्रतीत होता है।
निकोलस मिआरी

हालांकि यह दृष्टिकोण एक बेस व्यू कंट्रोलर विज्ञापन से दृश्य नियंत्रक को उप-वर्गीकृत करने के लिए पर्याप्त सामान्य है, जिसमें खारिज खारिज कर दिया गया है। लेकिन यह विफल रहता है यदि आप नेविगेशन व्यू कंट्रोलर में एक व्यू कंट्रोलर में लपेटने की कोशिश करते हैं
hariszaman

4
यह तब नहीं कहा जाता है जब उपयोगकर्ता शीर्ष से एक स्वाइप द्वारा मोडल व्यू कंट्रोलर को खारिज कर देता है!
दिमित्री

3
extension Foo: UIAdaptivePresentationControllerDelegate {
    func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
        //call whatever you want
    }
}

vc.presentationController?.delegate = foo

1
iOS 13.0+केवल
गोंडो

2

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

इस लिंक को देखने के लिए कि कैसे आराम से लीग बनाएं, https://stackoverflow.com/a/15839298/5647055

यह मानते हुए कि आपके "" रद्द करें "" बटन के लिए परिभाषित एक्शन विधि में, आप अपने सेग को सेट कर सकते हैं, आप इस रूप में सेगमेंट कर सकते हैं -

[self performSegueWithIdentifier:@"YourUnwindSegueName" sender:nil];

अब, जब भी आप VC2 में "रद्द करें" बटन दबाएंगे, इसे खारिज कर दिया जाएगा और VC1 दिखाई देगा। यह भी खोलना विधि कहेंगे, आपने VC1 में परिभाषित किया है। अब, आप जानते हैं कि प्रस्तुत दृश्य नियंत्रक कब खारिज किया जाता है।


2

मैं एक समन्वयक को संकेत देने के लिए निम्नलिखित का उपयोग करता हूं कि दृश्य नियंत्रक "किया गया" है। इसका उपयोग AVPlayerViewControllerटीवीओएस एप्लिकेशन में एक उपवर्ग में किया जाता है और प्लेयरवीसी बर्खास्तगी के संक्रमण के पूरा होने के बाद बुलाया जाएगा:

class PlayerViewController: AVPlayerViewController {
  var onDismissal: (() -> Void)?

  override func beginAppearanceTransition(_ isAppearing: Bool, animated: Bool) {
    super.beginAppearanceTransition(isAppearing, animated: animated)
    transitionCoordinator?.animate(alongsideTransition: nil,
      completion: { [weak self] _ in
         if !isAppearing {
            self?.onDismissal?()
        }
    })
  }
}

आपको AVPLayerViewController से वारिस नहीं होना चाहिए। Apple डॉक्स का कहना है: "AVPlayerViewController को उपवर्गित करना और इसके तरीकों को ओवरराइड करना समर्थित नहीं है, और अपरिभाषित व्यवहार का परिणाम है।"
नेरू

2

willMove(toParent: UIViewController?)निम्नलिखित तरीके का उपयोग करना मेरे लिए काम करने लगा। (IOS12 पर परीक्षण किया गया)।

override func willMove(toParent parent: UIViewController?) {
    super.willMove(toParent: parent);

    if parent == nil
    {
        // View controller is being removed.
        // Perform onDismiss action
    }
}

1

@ user523234 - "लेकिन VC1 में बर्खास्तगी दृश्य नियंत्रक की अनुमति नहीं दी जा रही थी।"

आप यह नहीं मान सकते कि VC1 वास्तव में प्रस्तुत करता है - यह रूट व्यू कंट्रोलर हो सकता है, VC0, कहते हैं। इसमें 3 दृश्य नियंत्रक शामिल हैं:

  • sourceViewController
  • presentingViewController
  • प्रस्तुत दृश्य नियंत्रक

अपने उदाहरण में, VC1 = sourceViewController, VC2 = presentedViewController, ?? = presentingViewController- हो सकता है VC1, शायद नहीं।

हालाँकि, आप हमेशा VC1.animationControllerForDismissedController पर भरोसा कर सकते हैं (कहा जा सकता है (यदि आपने प्रतिनिधि विधियों को लागू किया है) VC2 को खारिज करते समय और उस पद्धति में आप वही कर सकते हैं जो आप VC1 के साथ चाहते हैं।


1

मैंने इस पोस्ट को कई बार देखा है जब इस मुद्दे से निपटते हुए, मैंने सोचा कि मैं एक संभावित उत्तर पर कुछ प्रकाश डाल सकता हूं।

यदि आपको यह जानने की आवश्यकता है कि क्या उपयोगकर्ता द्वारा शुरू किए गए कार्य (जैसे स्क्रीन पर इशारे) यूआईएक्शनकंट्रोलर के लिए बर्खास्तगी में लगे हुए हैं , और उप-वर्ग या एक्सटेंशन या आपके कोड में जो कुछ भी है, उसे बनाने में समय का निवेश नहीं करना है।

यह पता चला है के रूप में, popoverPresentationController एक की संपत्ति UIActionController (या, बल्कि, उस प्रभाव के लिए किसी भी UIViewController), एक है प्रतिनिधि आप अपने कोड, प्रकार का है, जिसमें कभी भी सेट कर सकते हैं UIPopoverPresentationControllerDelegate , और निम्न विधियों है:

अपने एक्शन कंट्रोलर से डेलीगेट को असाइन करें, अपनी पद्धति (पसंद) को डेलिगेट क्लास (दृश्य, व्यू कंट्रोलर या जो भी हो), और वॉइला में लागू करें!

उम्मीद है की यह मदद करेगा।


और उन लोगों को आईओएस से हटा दिया गया है 13. Doh
बेन एफ्लेक


0
  1. एक वर्ग फ़ाइल (.h / .m) बनाएं और इसे नाम दें: DismissSegue
  2. उप-वर्ग का चयन करें: UIStoryboardSegue

  3. DismissSegue.m फ़ाइल पर जाएं और निम्नलिखित कोड लिखें:

    - (void)perform {
        UIViewController *sourceViewController = self.sourceViewController;
        [sourceViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
    }
    
  4. स्टोरीबोर्ड खोलें और फिर Ctrl + कैंसिल बटन से VC1 तक खींचें और Dismiss के रूप में Action Segue का चयन करें और आप कर रहे हैं।


0

यदि आप दृश्य नियंत्रक के मंद होने पर ओवरराइड करते हैं:

override func removeFromParentViewController() {
    super.removeFromParentViewController()
    // your code here
}

कम से कम मेरे लिए यह काम किया।


@ जॉनस्ल्को सच नहीं है, "देशी" दृश्य नियंत्रक पदानुक्रम में से कुछ बच्चे / माता-पिता आदिम के साथ खुद को लागू करते हैं।
mxcl


0

overrideआईएनजी viewDidAppearने मेरे लिए चाल चली। मैंने अपने मोडल में एक सिंगलटन का उपयोग किया और अब कॉलिंग वीसी, मोडल और हर जगह सेट करने में सक्षम हूं।


viewDidAppear?
दिमित्री

1
क्या आपका मतलब डिडीडिसैपियर है?
डेल

0

viewWillDisappearप्रस्तुत दृश्य नियंत्रक में फ़ंक्शन को ओवरराइड करें ।

override func viewWillDisappear(_ animated: Bool) {
    //Your code here
}

इसके साथ युग्मित किए बिना यह सही ढंग से काम नहीं करता है viewDidAppear
दिमित्री

1
Super.viewWillDisappear
Dale

0

जैसा कि उल्लेख किया गया है, समाधान का उपयोग करना है override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil)

उन लोगों के लिए जो override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil)हमेशा काम में नहीं लगते हैं, आप सोच सकते हैं कि UINavigationControllerयदि यह प्रबंधित किया जा रहा है तो कॉल को इंटरसेप्ट किया जा रहा है। मैंने एक उपवर्ग लिखा है जिसकी मदद करनी चाहिए:

class DismissingNavigationController: UINavigationController { override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) { super.dismiss(animated: flag, completion: completion) topViewController?.dismiss(animated: flag, completion: completion) } }


0

यदि आप व्यू कंट्रोलर को बर्खास्त करना चाहते हैं, तो आपको नीचे दिए गए कोड का उपयोग करना चाहिए।

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    if (self.isBeingDismissed && self.completion != NULL) {
        self.completion();
    }
}

दुर्भाग्य से हम ओवरराइड विधि में पूर्णता को नहीं कह सकते हैं - (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^ _Nullable)(void))completion;क्योंकि इस पद्धति को केवल तभी कहा जाता है जब आप इस दृश्य नियंत्रक की बर्खास्तगी विधि कहते हैं।


लेकिन viewWillDisappearयह भी सही से काम नहीं करता है viewDidAppear
दिमित्री

जब वीसी पूरी तरह से कवर किया जाता है (जैसे एक मॉडल के साथ)। आप को खारिज नहीं किया जा सकता है
लो फ्रेंको

0

मैं ViewController के लिए deinit का उपयोग किया है

deinit {
    dataSource.stopUpdates()
}

क्लास इंक्लॉस्केट होने से ठीक पहले एक डीइन्यूएस्टाइज़र कहा जाता है।

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