UIViewController पर UIViewController प्रस्तुत करने का प्रयास करें जिसका दृश्य खिड़की पदानुक्रम में नहीं है


599

बस Xcode 4.5 का उपयोग करना शुरू किया और मुझे कंसोल में यह त्रुटि मिली:

चेतावनी: प्रस्तुत करने का प्रयास करें <finishViewController: 0x1e56e0a0> पर <ViewController: 0x1ec3e000> जिसका दृश्य विंडो पदानुक्रम में नहीं है!

दृश्य अभी भी प्रस्तुत किया जा रहा है और ऐप में सब कुछ ठीक काम कर रहा है। क्या यह iOS 6 में कुछ नया है?

यह वह कोड है जिसे मैं विचारों के बीच बदलने के लिए उपयोग कर रहा हूं:

UIStoryboard *storyboard = self.storyboard;
finishViewController *finished = 
[storyboard instantiateViewControllerWithIdentifier:@"finishViewController"];

[self presentViewController:finished animated:NO completion:NULL];

3
मेरे पास एक ही समस्या है, presentViewController:animated:completionएक नव नियंत्रक पर कॉल करने की कोशिश करने के अलावा । क्या आप ऐप प्रतिनिधि में ऐसा कर रहे हैं?
टारनफेल्ड

नहीं, मैं इसे एक व्यू कंट्रोलर से दूसरे में कर रहा हूं। क्या आपने कोई समाधान पाया है?
काइल गोस्लान

कोड का एक हिस्सा पर समान मुद्दा जो हमेशा Xcode 4.5 का उपयोग करने से पहले काम करता था, मैं एक UINavigationController प्रस्तुत कर रहा हूं, लेकिन फिर से यह हमेशा पहले काम किया है।
इमानुएल फुमगल्ली 14

मुझे एक ही समस्या है, हल नहीं है। यह एप्लिकेशन प्रतिनिधि से कर रहा है, और रूटव्यूकंट्रोलर कॉलिंग "presentViewController" एक UITabBarController मधुमक्खी।
डार्कसाइडर

3
इसके अलावा, अगर
मेकएंडविविअल को

जवाबों:


1296

आप इस विधि को कहां से बुला रहे हैं? मेरे पास एक मुद्दा था जहां मैं viewDidLoadविधि के भीतर एक मोडल व्यू कंट्रोलर प्रस्तुत करने का प्रयास कर रहा था । मेरे लिए समाधान यह था कि इस कॉल को viewDidAppear:विधि में ले जाया जाए ।

मेरा अनुमान है कि दृश्य नियंत्रक का दृष्टिकोण नहीं है का कहना है कि यह लोड किया गया है (जब से खिड़की के दृश्य पदानुक्रम मेंviewDidLoadसंदेश भेजे जाने के), लेकिन यह है खिड़की पदानुक्रम में के बाद यह प्रस्तुत किया गया है (जबviewDidAppear:संदेश भेजे जाने के) ।


सावधान

यदि आप कॉल करते हैं presentViewController:animated:completion:, तो viewDidAppear:आप एक ऐसे मुद्दे पर चल सकते हैं, जिसके तहत मोडल व्यू कंट्रोलर को हमेशा प्रस्तुत किया जा सकता है, जब भी व्यू कंट्रोलर का व्यू (जो समझ में आता है!) और इसलिए मोडल व्यू कंट्रोलर को प्रस्तुत किया जा रहा है, कभी नहीं जाएगा .. ।

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


6
@James आप सही हैं, देखने जाहिरा तौर पर जब तक पदानुक्रम में नहीं है के बाद और viewWillAppear हल किया गया है एक बार viewDidAppear बुलाया गया है। यदि यह मेरा प्रश्न होता तो मैं इस उत्तर को स्वीकार करता;)
मैट मैक

6
@ जेम्स थैंक्स ViewDidAppear के उपयोग से मेरे लिए भी समस्या हल हो गई। समझ में आता है।
अली

44
काश मैं इसे दो बार बढ़ा सकता। मुझे बस यह समस्या थी और यह पता लगाने के लिए धागे पर आया कि मैंने पिछली बार इसे देखा था।
शकरवेल

7
ध्यान दें कि जब आप VCD को viewDidAppear में बदलते हैं, तो यह एनीमेशन के साथ एक सेगमेंट के निष्पादन का कारण बनता है। पृष्ठभूमि की एक फ्लैश / प्रदर्शन का कारण बनता है।
विंसेंट

2
हाँ यह ट्रिक व्यूवेलपियर है: (BOOL) एनिमेटेड जैसा कि यह सही है। एक और महत्वपूर्ण बात यह है कि आपको विधि में सुपर को कॉल करना होगा, जैसा कि [सुपर viewDidAppear: animated]; इसके बिना यह काम नहीं कर रहा है।
बूटमेकर

66

एक अन्य संभावित कारण:

मेरे पास यह मुद्दा था जब मैं गलती से एक ही दृश्य नियंत्रक को दो बार प्रस्तुत कर रहा था। (एक बारperformSegueWithIdentifer:sender: जिसके बटन दबाए जाने पर कॉल किया गया था, और दूसरी बार बटन से सीधे जुड़े हुए सेगमेंट के साथ)।

प्रभावी रूप से, दो सेगमेंट एक ही समय में फायरिंग कर रहे थे, और मुझे त्रुटि मिली: Attempt to present X on Y whose view is not in the window hierarchy!


4
मेरे पास एक ही त्रुटि थी, और आपके जवाब से मुझे यह पता लगाने में मदद मिली कि क्या चल रहा था, यह वास्तव में यह त्रुटि थी, इसे आप के कारण ठीक किया, धन्यवाद, +1
samouray

1
मैंने पुराने सेगमेंट को हटा दिया और वीसी को वीसी से जोड़ा। क्या वीसी को स्टोरीबोर्ड में बटन कनेक्ट करने का एक तरीका है क्योंकि यह तरीका मेरे लिए बस गलत है?
एमसीबी

मेरे पास एक ही त्रुटि थी, आपके उत्तर ने मेरी समस्या को हल कर दिया, आपके ध्यान के लिए धन्यवाद। सधन्यवाद।
इम्बुरक

1
योग्य, गलती से मैं भी दो वीसी बना रहा था: बटन और PerformSegue से, टिप के लिए धन्यवाद !!!
बोरज

1
मेरे मामले में मैं present(viewController, animated: true, completion: nil)एक लूप के अंदर बुला रहा था ।
समो

38

viewWillLayoutSubviewsऔर viewDidLayoutSubviews(iOS 5.0+) का उपयोग इस उद्देश्य के लिए किया जा सकता है। उन्हें viewDidAppear की तुलना में पहले कहा जाता है।


3
फिर भी उनका उपयोग अन्य अवसरों में भी किया जाता है, इसलिए मुझे लगता है कि उन्हें एक दृश्य के "जीवनकाल" में कई बार कहा जा सकता है।
जॉनी

यह भी नहीं है कि क्या तरीके हैं - जैसा कि नाम से पता चलता है। viewDidAppear सही है। दृश्य चक्र पर पढ़ना एक अच्छा विचार है।
टूलूजर

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

अलर्ट प्रदर्शित करने का प्रयास करते समय इस उत्तर ने मेरे लिए सबसे अच्छा काम किया। जब मैं इसे viewDidLoad और viewWillAppear में डालता हूं तो अलर्ट दिखाई नहीं देगा।
uplearnedu.com

26

मुख्य दृश्य के लिए किसी भी सबव्यू को प्रदर्शित करने के लिए, कृपया निम्नलिखित कोड का उपयोग करें

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

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

[yourCurrentViewController presentViewController:composeViewController animated:YES completion:nil];

मुख्य दृश्य से किसी भी सबव्यू को खारिज करने के लिए, कृपया निम्नलिखित कोड का उपयोग करें

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

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

[yourCurrentViewController dismissViewControllerAnimated:YES completion:nil];

मेरे लिए भी काम किया
अजीज जावेद

17

मुझे भी इस समस्या का सामना करना पड़ा जब मैंने एक UIViewControllerमें प्रस्तुत करने की कोशिश की viewDidLoad। जेम्स बेडफोर्ड के जवाब ने काम किया, लेकिन मेरे ऐप ने पृष्ठभूमि को पहले 1 या 2 सेकंड के लिए दिखाया।

कुछ शोध के बाद, मैंने इसका उपयोग करके इसे हल करने का एक तरीका ढूंढ लिया है addChildViewController

- (void)viewDidLoad
{
    ...
    [self.view addSubview: navigationViewController.view];
    [self addChildViewController: navigationViewController];
    ...
}

9
मुझे लगता है कि आप याद कर रहे हैं [NavigationViewController didMoveToParentViewController: self]
फ़ूफ़ॉक्स

2
मैंने फ़ॉफ़ॉक्स के सुझाव के साथ, आपके कोड की कोशिश की, और जब मैं इसे माता-पिता से निकालने के लिए जाता हूं, तो यह नहीं चलेगा। Lololol। फिर भी बिना किसी फिक्स के अटक गया।
लोगिक्सॉरस रेक्स

स्विफ्ट 3.1 में काम करता है
कांग

प्रेजीडेक्स्टर्रोलर से पहले इस्तेमाल होने वाली दो लाइनों के ऊपर @sunkehappy, लेकिन इसका क्रैश क्यों हुआ?
अय्यप्पन रवि

14

शायद, मेरी तरह, आपके पास एक गलत जड़ है viewController

मैं ViewControllerएक non-UIViewControllerसंदर्भ में प्रदर्शित करना चाहता हूं ,

इसलिए मैं ऐसे कोड का उपयोग नहीं कर सकता:

[self presentViewController:]

तो, मुझे एक UIViewController मिलता है:

[[[[UIApplication sharedApplication] delegate] window] rootViewController]

किसी कारण (तार्किक बग) के लिए, rootViewControllerउम्मीद (एक सामान्य UIViewController) के अलावा कुछ और है । तब मैं बग को ठीक करता हूं, rootViewControllerए की जगह UINavigationController, और समस्या दूर हो गई है।


8

TL; DR आप केवल 1 rootViewController और इसके सबसे हाल ही में प्रस्तुत किया जा सकता है। इसलिए जब वह पहले से ही बर्खास्त नहीं किया गया है, तो एक व्यूकंट्रोलर दूसरे व्यू कॉन्ट्रॉलर को पेश करने की कोशिश न करें।

अपने खुद के कुछ परीक्षण करने के बाद मैं एक निष्कर्ष पर पहुंचा हूं।

यदि आपके पास एक rootViewController है जिसे आप सब कुछ पेश करना चाहते हैं तो आप इस समस्या में भाग सकते हैं।

यहां मेरा रूटकंट्रोलर कोड है (ओपन रूट से व्यूकंट्रोलर प्रस्तुत करने के लिए मेरा शॉर्टकट है)।

func open(controller:UIViewController)
{
    if (Context.ROOTWINDOW.rootViewController == nil)
    {
        Context.ROOTWINDOW.rootViewController = ROOT_VIEW_CONTROLLER
        Context.ROOTWINDOW.makeKeyAndVisible()
    }

    ROOT_VIEW_CONTROLLER.presentViewController(controller, animated: true, completion: {})
}

अगर मैं एक पंक्ति में दो बार खुला कॉल करता हूं (समय की परवाह किए बिना), यह पहले खुले पर ठीक काम करेगा, लेकिन दूसरे खुले पर नहीं। दूसरा खुला प्रयास उपरोक्त त्रुटि के परिणामस्वरूप होगा।

हालाँकि अगर मैं सबसे हाल ही में प्रस्तुत किया गया दृश्य बंद कर देता हूं तो कॉल ओपन करें, यह तब ठीक काम करता है जब मैं दोबारा कॉल करता हूं (दूसरे व्यू-कॉन्ट्रैक्टर पर)।

func close(controller:UIViewController)
{
    ROOT_VIEW_CONTROLLER.dismissViewControllerAnimated(true, completion: nil)
}

मैंने जो निष्कर्ष निकाला है वह यह है कि केवल MOST-RECENT-CALL का rootViewController दृश्य पदानुक्रम पर है (भले ही आपने इसे खारिज नहीं किया हो या कोई दृश्य न हटाएं)। मैंने सभी लोडर कॉल (viewDidLoad, viewDidAppear, और विलंबित कॉल को कॉल करते हुए) के साथ खेलने का प्रयास किया और मैंने पाया है कि जिस तरह से मैं इसे काम कर सकता था वह केवल शीर्ष सबसे दृश्य नियंत्रक से मौजूद कॉलिंग है।


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

हाँ सब ठीक है और अच्छा है, लेकिन इसका क्या हल है ... मेरे पास एक बैकग्राउंड वर्कर थ्रेड है जो एक सर्वर पर जा रहा है और दाएं और मध्य में स्टोरीबोर्ड प्रदर्शित कर रहा है और पूरी कार्यप्रणाली फर्जी है .. यह भयानक है .. क्या होना चाहिए एक हवा पूरी तरह से एक है मजाक इसलिए क्योंकि मैं चाहता हूं कि वह बैकग्राउंड थ्रेड wait wait decide push screen to frontइंट्रस्ट करे : और यह इम्पॉसिबल है IOS ????
श्री हील्स

5

मेरे मुद्दा था मैं में segue प्रदर्शन कर रहा था UIApplicationDelegateकी didFinishLaunchingWithOptionsविधि इससे पहले कि मैं कहा जाता है makeKeyAndVisible()खिड़की पर।


कैसे? क्या आप विस्तार से समझा सकते हैं? मैं उसी समस्या का सामना कर रहा हूँ। के रूप में UIViewController self.window .rootViewController = initialViewControlleripad self.window .makeKeyAndVisible ()?: UIViewController = mainStoryboardIpad.instantiateViewController ( "SplashController" withIdentifier:) यह मेरा कोड जाने initialViewControlleripad है
shahtaj खालिद

4

मेरी स्थिति में, मैं एक वर्ग के ओवरराइड में मुझे डालने में सक्षम नहीं था। तो, यहाँ है कि मुझे क्या मिला:

let viewController = self // I had viewController passed in as a function,
                          // but otherwise you can do this


// Present the view controller
let currentViewController = UIApplication.shared.keyWindow?.rootViewController
currentViewController?.dismiss(animated: true, completion: nil)

if viewController.presentedViewController == nil {
    currentViewController?.present(alert, animated: true, completion: nil)
} else {
    viewController.present(alert, animated: true, completion: nil)
}

3

मुझे भी यही समस्या थी। मुझे एक नेविगेशन नियंत्रक को एम्बेड करना था और इसके माध्यम से नियंत्रक को प्रस्तुत करना था। नीचे नमूना कोड है।

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    UIImagePickerController *cameraView = [[UIImagePickerController alloc]init];
    [cameraView setSourceType:UIImagePickerControllerSourceTypeCamera];
    [cameraView setShowsCameraControls:NO];

    UIView *cameraOverlay = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 768, 1024)];
    UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"someImage"]];
    [imageView setFrame:CGRectMake(0, 0, 768, 1024)];
    [cameraOverlay addSubview:imageView];

    [cameraView setCameraOverlayView:imageView];

    [self.navigationController presentViewController:cameraView animated:NO completion:nil];
//    [self presentViewController:cameraView animated:NO completion:nil]; //this will cause view is not in the window hierarchy error

}

3

यदि आपके पास खेले गए वीडियो के साथ AVPlayer ऑब्जेक्ट है, तो आपको पहले वीडियो को रोकना होगा।


मेरा मतलब है कि वीडियो को पहले रोका / रोका जाना चाहिए।
व्लाद

वास्तव में यह मेरे में मदद की, यह मुझे इस के बाद नेतृत्व stackoverflow.com/questions/20746413/...
उमर एन शामली

3

मेरी भी यही समस्या थी। समस्या यह थी, PerformSegueWithIdentifier को एक सूचना द्वारा ट्रिगर किया गया था, जैसे ही मैंने अधिसूचना को मुख्य धागे पर रखा था चेतावनी संदेश चला गया था।


3

यह ठीक काम कर रहा है यह कोशिश करो। संपर्क

UIViewController *top = [UIApplication sharedApplication].keyWindow.rootViewController;
[top presentViewController:secondView animated:YES completion: nil];

3

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

इसलिए संक्षेप में, जो भी आप कर रहे हैं सुनिश्चित करें कि मोडल को एक से अधिक बार नहीं कहा जा रहा है


3

मैंने एक ऐसे कोड के साथ समाप्त किया है जो अंत में मेरे (स्विफ्ट) काम करता है, यह देखते हुए कि आप viewControllerवस्तुतः कहीं से भी कुछ प्रदर्शित करना चाहते हैं । जब कोई rootViewController उपलब्ध नहीं होगा, तो यह कोड स्पष्ट रूप से दुर्घटनाग्रस्त हो जाएगा। इसमें आमतौर पर यूआई थ्रेड का उपयोग करने के लिए आवश्यक स्विच शामिल नहीं है

dispatch_sync(dispatch_get_main_queue(), {
    guard !NSBundle.mainBundle().bundlePath.hasSuffix(".appex") else {
       return; // skip operation when embedded to App Extension
    }

    if let delegate = UIApplication.sharedApplication().delegate {
        delegate.window!!.rootViewController?.presentViewController(viewController, animated: true, completion: { () -> Void in
            // optional completion code
        })
    }
}

BTW को समझने के लिए कि मैं इस विधि को कहाँ से कहता हूँ ... यह अन्यथा UI-कम SDK लाइब्रेरी है, जो आपके यूआई को निश्चित (अघोषित) मामले में आपके ऐप पर प्रदर्शित करती है।
.ग्रेसचेंग

आप दुर्घटना करेंगे और जलाएंगे अगर कोई भी आपको एक ऐप में एसडीके एम्बेड करने का फैसला करता है जिसमें एक एक्सटेंशन है। एक UIViewController पारित करने के लिए आप init विधि का दुरुपयोग करने के लिए [s]।
एंटोन ट्रोपास्को

तुम सच्चे एंटोन हो। यह कोड तब लिखा गया था जब एक्सटेंशन्स मौजूद नहीं थे और एसडीके उन में से किसी में भी उपयोग नहीं किया गया है। मैंने इस किनारे-केस को छोड़ने के लिए एक गार्ड क्लॉज जोड़ा है।
.ग्रेगचैच

3

चेतावनी इस तरह मतलब हो सकता है कि आप वर्तमान नया करने के लिए कोशिश कर रहे हैं View Controllerके माध्यम से Navigation Controllerहै, जबकि इस Navigation Controllerवर्तमान में एक और प्रस्तुत कर रहा है View Controller। इसे ठीक करने के लिए आपको वर्तमान में प्रस्तुत किए गए को खारिज करना होगा View Controllerऔर पूरा होने पर नया प्रस्तुत करना होगा। चेतावनी का एक और कारण View Controllerथ्रेड पर पेश करने की कोशिश कर सकता है main


2

मैंने इसे पूर्ण ब्लॉक के start()अंदर फ़ंक्शन को स्थानांतरित करके तय किया dismiss:

self.tabBarController.dismiss(animated: false) {
  self.start()
}

प्रारंभ में self.present()UINavigationController के लिए एक के लिए दो कॉल होते हैं और एक के लिए दूसरा कॉल होता है UIImagePickerController

उसने मेरे लिए इसे हल कर दिया।


2

मेरा स्विफ्ट 4.2 पर भी ऐसा ही मुद्दा था, लेकिन मेरा विचार दृश्य चक्र से प्रस्तुत नहीं किया गया था। मैंने पाया कि मेरे पास एक ही समय में प्रस्तुत किए जाने वाले कई सेगमेंट थे। इसलिए मैंने dispatchAsyncAfter का उपयोग किया।

func updateView() {

 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in

// for programmatically presenting view controller 
// present(viewController, animated: true, completion: nil)

//For Story board segue. you will also have to setup prepare segue for this to work. 
 self?.performSegue(withIdentifier: "Identifier", sender: nil)
  }
}

1

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


1

नीचे लाइन में लिखना है।

self.searchController.definesPresentationContext = true

के बजाय

self.definesPresentationContext = true

UIViewController में


1

स्विफ्ट 3 के साथ ...

इसका एक और संभावित कारण, जो मेरे साथ हुआ था, एक टेबल व्यूसेल से एक और ViewController स्टोरीबोर्ड पर एक सेगमेंट था। मैंने भी इस्तेमाल कियाoverride func prepare(for segue: UIStoryboardSegue, sender: Any?) {}जब सेल पर क्लिक किया गया था तब था।

मैंने ViewController से ViewController का एक सेगमेंट बनाकर इस मुद्दे को ठीक किया।


1

मेरे पास यह मुद्दा था, और मूल कारण कई बार एक बटन क्लिक हैंडलर (टचअप इंसाइड) की सदस्यता थी।

यह ViewWillAppear में सदस्यता ले रहा था, जिसे कई बार कहा जा रहा था क्योंकि हमने दूसरे नियंत्रक पर जाने के लिए नेविगेशन जोड़ा था, और फिर इसे वापस खोल दिया।


1

मेरे साथ ऐसा हुआ कि स्टोरीबोर्ड में सेग किसी तरह टूट गया था । सेग्मेंट को हटाना (और फिर से उसी सीग्यू को बनाना) ने इस समस्या को हल कर दिया।


1

आपकी मुख्य विंडो के साथ, संभवतया ऐसे संक्रमणों के साथ समय होगा जो अलर्ट प्रस्तुत करने के साथ असंगत हैं। अपने आवेदन जीवनचक्र में किसी भी समय अलर्ट प्रस्तुत करने की अनुमति देने के लिए, आपके पास कार्य करने के लिए एक अलग विंडो होनी चाहिए।

/// independant window for alerts
@interface AlertWindow: UIWindow

+ (void)presentAlertWithTitle:(NSString *)title message:(NSString *)message;

@end

@implementation AlertWindow

+ (AlertWindow *)sharedInstance
{
    static AlertWindow *sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[AlertWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
    });
    return sharedInstance;
}

+ (void)presentAlertWithTitle:(NSString *)title message:(NSString *)message
{
    // Using a separate window to solve "Warning: Attempt to present <UIAlertController> on <UIViewController> whose view is not in the window hierarchy!"
    UIWindow *shared = AlertWindow.sharedInstance;
    shared.userInteractionEnabled = YES;
    UIViewController *root = shared.rootViewController;
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    alert.modalInPopover = true;
    [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
        shared.userInteractionEnabled = NO;
        [root dismissViewControllerAnimated:YES completion:nil];
    }]];
    [root presentViewController:alert animated:YES completion:nil];
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    self.userInteractionEnabled = NO;
    self.windowLevel = CGFLOAT_MAX;
    self.backgroundColor = UIColor.clearColor;
    self.hidden = NO;
    self.rootViewController = UIViewController.new;

    [NSNotificationCenter.defaultCenter addObserver:self
                                           selector:@selector(bringWindowToTop:)
                                               name:UIWindowDidBecomeVisibleNotification
                                             object:nil];

    return self;
}

/// Bring AlertWindow to top when another window is being shown.
- (void)bringWindowToTop:(NSNotification *)notification {
    if (![notification.object isKindOfClass:[AlertWindow class]]) {
        self.hidden = YES;
        self.hidden = NO;
    }
}

@end

मूल उपयोग, जो डिजाइन द्वारा, हमेशा सफल होगा:

[AlertWindow presentAlertWithTitle:@"My title" message:@"My message"];

1

अफसोस की बात है कि स्वीकृत समाधान मेरे मामले के लिए काम नहीं किया। मैं दूसरे व्यू कंट्रोलर से प्राप्त होने के बाद एक नए व्यू कंट्रोलर पर नेविगेट करने का प्रयास कर रहा था।

मैंने संकेत करने के लिए एक ध्वज का उपयोग करके एक समाधान पाया कि कौन सा खोलना लीग कहा जाता था।

@IBAction func unwindFromAuthenticationWithSegue(segue: UIStoryboardSegue) {
    self.shouldSegueToMainTabBar = true
}

@IBAction func unwindFromForgetPasswordWithSegue(segue: UIStoryboardSegue) {
    self.shouldSegueToLogin = true
}

फिर वांछित कुलपति के साथ प्रस्तुत करें present(_ viewControllerToPresent: UIViewController)

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    if self.shouldSegueToMainTabBar {
        let mainTabBarController = storyboard.instantiateViewController(withIdentifier: "mainTabBarVC") as! MainTabBarController
        self.present(mainTabBarController, animated: true)
        self.shouldSegueToMainTabBar = false
    }
    if self.shouldSegueToLogin {
        let loginController = storyboard.instantiateViewController(withIdentifier: "loginVC") as! LogInViewController
        self.present(loginController, animated: true)
        self.shouldSegueToLogin = false
    }
}

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


1

मैंने यह त्रुटि स्थिरांक में सबसे अधिक व्यू-कॉन्ट्रैक्टर को स्टोर करने के साथ तय की है, जो रूट-व्यूकुलर पर चक्र के दौरान पाया जाता है:

if var topController = UIApplication.shared.keyWindow?.rootViewController {
    while let presentedViewController = topController.presentedViewController {
        topController = presentedViewController
    }
    topController.present(controller, animated: false, completion: nil)
    // topController should now be your topmost view controller
}

1

मैंने पाया कि यह बग Xcode को अपडेट करने के बाद आया है, मुझे स्विफ्ट 5 पर विश्वास है । समस्या तब हो रही थी जब मैंने एक दृश्य नियंत्रक को सीधे हटाने के बाद प्रोग्राम को सीधे लॉन्च किया था।

संबंधित बग को ठीक करते हुए समाधान आ गया, जो यह है कि उपयोगकर्ता अब पृष्ठ को नीचे स्वाइप करके लीग को खोल सकता है। इसने मेरे कार्यक्रम के तर्क को तोड़ दिया।

यह स्वचालित से पूर्ण स्क्रीन तक सभी दृश्य नियंत्रकों पर प्रस्तुति मोड को बदलकर तय किया गया था

आप इसे इंटरफ़ेस बिल्डर में गुण पैनल में कर सकते हैं। या इस उत्तर को प्रोग्राम के रूप में कैसे करें, इसके लिए देखें ।


0

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

तो हाँ, यह "जादुई तरीके से सही तरीके से खोजने" के बारे में नहीं है, यह समझने के बारे में है कि आपका कोड कहाँ खड़ा है और यह क्या कर रहा है। मुझे खुशी है कि Apple ने इस तरह के सादे-अंग्रेजी चेतावनी संदेश दिए, यहां तक ​​कि भावना के साथ भी। कुदोस ने सेब देव को जो किया !!


0

यदि अन्य समाधान किसी कारण से अच्छे नहीं लगते हैं, तो आप अभी भी workaround0 की देरी से प्रस्तुत करने के इस पुराने का उपयोग कर सकते हैं , जैसे:

dispatch_after(0, dispatch_get_main_queue(), ^{
    finishViewController *finished = [self.storyboard instantiateViewControllerWithIdentifier:@"finishViewController"];
    [self presentViewController:finished animated:NO completion:NULL];    
});

जब मैंने कोई प्रलेखित गारंटी नहीं देखी है कि आपका वीसी उस समय पदानुक्रम पर होगा जब प्रेषण ब्लॉक निष्पादन के लिए निर्धारित है, मैंने देखा है कि यह ठीक काम करेगा।

उदाहरण के लिए 0.2 सेकंड की देरी का उपयोग करना भी एक विकल्प है। और सबसे अच्छी बात - इस तरह से आपको बूलियन चर के साथ गड़बड़ करने की आवश्यकता नहीं हैviewDidAppear:


2
हालांकि यह अब काम कर सकता है, इस बात की कोई गारंटी नहीं है कि Apple व्यवहार को बदल देगा और भविष्य में आप पर यह टूटेगा। फिर जब आप अपने कोड को देखने और चीजों को फिर से ठीक करने के लिए वापस जाते हैं, तो आपको आश्चर्य होगा कि आप यह अनावश्यक अनावश्यक प्रेषण क्यों कर रहे थे।
क्रूजिन

0 समय के साथ डिस्पैच ने मुझे पहले से ही कई बार बचाया है - कभी-कभी ऐसी चीजें जो केवल तार्किक रूप से काम करनी चाहिए, वे इसके बिना सामान्य रूप से काम नहीं करती हैं। तो बस अपने और दूसरों के लिए टिप्पणी करें कि आप क्यों नहीं करते हैं (केवल इस तरह के एक प्रेषण) और आप ठीक होना चाहिए।
डैनी पी '

2
आप समस्या को हल कर रहे हैं और इसे हल नहीं कर रहे हैं।
माइकल पीटरसन

0

यह किसी भी दृश्य नियंत्रक को पेश करने के लिए काम करता है, यदि आपके पास नेविगेशन नियंत्रक उपलब्ध है। self.navigationController।

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