presentViewController: एनिमेटेड: हाँ दृश्य तब तक दिखाई नहीं देगा जब तक उपयोगकर्ता फिर से टैप नहीं करता


93

मेरे साथ कुछ अजीब व्यवहार हो रहा है presentViewController:animated:completion। मैं जो बना रहा हूं वह अनिवार्य रूप से एक अनुमान लगाने का खेल है।

मेरे पास एक UIViewControllerफ्रीक्वेंसी (फ्रीक्वेंसी व्यू कंट्रोलर) है जिसमें एक UITableViewफ्रीक्वेंसी (फ्रीटेबल व्यू) है। जब उपयोगकर्ता प्रश्न के उत्तर में पंक्ति पर टैप करता है जिसमें सही उत्तर होता है, तो एक दृश्य (correctViewController) तत्काल होना चाहिए और इसका दृश्य स्क्रीन के नीचे से, एक मोडल दृश्य के रूप में स्लाइड होना चाहिए। यह उपयोगकर्ता को बताता है कि उनके पास एक सही उत्तर है और अगले प्रश्न के लिए तैयार आवृत्तिदृश्यकंट्रोलर को इसके पीछे रीसेट करता है। correctViewController अगले सवाल का खुलासा करने के लिए एक बटन प्रेस पर खारिज कर दिया है।

यह सब हर बार सही ढंग से काम करता है, और सही व्यू कॉन्ट्रोलर का नजरिया तब तक तुरंत दिखाई देता है जब तक वह presentViewController:animated:completionहै animated:NO

अगर मैं सेट करता हूं animated:YES, तो correctViewController को इनिशियलाइज़ किया जाता है और कॉल किया जाता है viewDidLoad। हालाँकि viewWillAppear, viewDidAppearऔर पूरा होने वाले ब्लॉक presentViewController:animated:completionको नहीं कहा जाता है। जब तक मैं एक दूसरा टैप नहीं करता, तब तक ऐप केवल फ्रीक्वेंसी व्यू कंट्रोलर दिखाता है। अब, viewWillAppear, viewDidAppear और पूर्णता ब्लॉक को कहा जाता है।

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

मैं वास्तव में इस बारे में क्या करना है के रूप में एक नुकसान में हूँ ... मैं वास्तव में किसी भी मदद प्रदान कर सकते हैं किसी की सराहना करेंगे।

धन्यवाद

यहाँ मेरा कोड है। यह बहुत आसान है ...

यह questionViewController में कोड है जो questionTableView के प्रतिनिधि के रूप में कार्य करता है

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

    if (indexPath.row != [self.frequencyModel currentFrequencyIndex])
    {
        // If guess was wrong, then mark the selection as incorrect
        NSLog(@"Incorrect Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
        UITableViewCell *cell = [self.frequencyTableView cellForRowAtIndexPath:indexPath];
        [cell setBackgroundColor:[UIColor colorWithRed:240/255.0f green:110/255.0f blue:103/255.0f alpha:1.0f]];            
    }
    else
    {
        // If guess was correct, show correct view
        NSLog(@"Correct Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
        self.correctViewController = [[HFBCorrectViewController alloc] init];
        self.correctViewController.delegate = self;
        [self presentViewController:self.correctViewController animated:YES completion:^(void){
            NSLog(@"Completed Presenting correctViewController");
            [self setUpViewForNextQuestion];
        }];
    }
}

यह सही ViewController के पूरे है

@implementation HFBCorrectViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self)
    {
        // Custom initialization
        NSLog(@"[HFBCorrectViewController initWithNibName:bundle:]");
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    NSLog(@"[HFBCorrectViewController viewDidLoad]");
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    NSLog(@"[HFBCorrectViewController viewDidAppear]");
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)close:(id)sender
{
    NSLog(@"[HFBCorrectViewController close:sender:]");
    [self.delegate didDismissCorrectViewController];
}


@end

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

मुझे यह प्रश्न पहले मिला था: UITableView और presentViewController प्रदर्शित करने के लिए 2 क्लिक लेता है

और अगर मैं अपना didSelectRowकोड इसे बदल देता हूं , तो यह एनीमेशन के साथ बहुत समय तक काम करता है ... लेकिन यह गड़बड़ है और यह समझ में नहीं आता है कि यह पहली जगह में काम क्यों नहीं करता है। इसलिए मुझे लगता है कि एक जवाब के रूप में गिनती नहीं है ...

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

    if (indexPath.row != [self.frequencyModel currentFrequencyIndex])
    {
        // If guess was wrong, then mark the selection as incorrect
        NSLog(@"Incorrect Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);
        UITableViewCell *cell = [self.frequencyTableView cellForRowAtIndexPath:indexPath];
        [cell setBackgroundColor:[UIColor colorWithRed:240/255.0f green:110/255.0f blue:103/255.0f alpha:1.0f]];
        // [cell setAccessoryType:(UITableViewCellAccessoryType)]

    }
    else
    {
        // If guess was correct, show correct view
        NSLog(@"Correct Guess: %@", [self.frequencyModel frequencyLabelAtIndex:(int)indexPath.row]);

        ////////////////////////////
        // BELOW HERE ARE THE CHANGES
        [self performSelector:@selector(showCorrectViewController:) withObject:nil afterDelay:0];
    }
}

-(void)showCorrectViewController:(id)sender
{
    self.correctViewController = [[HFBCorrectViewController alloc] init];
    self.correctViewController.delegate = self;
    self.correctViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
    [self presentViewController:self.correctViewController animated:YES completion:^(void){
        NSLog(@"Completed Presenting correctViewController");
        [self setUpViewForNextQuestion];
    }];
}

1
मेरी भी यही समस्या है। मैंने NSLogs के साथ जाँच की कि मैं किसी भी तरीके को कॉल नहीं करता हूं जिसे निष्पादित करने में लंबा समय लगता है। ऐसा प्रतीत होता है कि यह सिर्फ एक एनीमेशन presentViewController:है जिसे ट्रिगर करना चाहिए एक बड़ी देरी से शुरू होता है। यह iOS 7 में बग प्रतीत होता है और Apple Dev Forums में भी चर्चा में है।
थियो

मेरी भी यही समस्या है। एक iOS7 बग की तरह लगता है - iOS6 पर नहीं होता है। इसके अलावा, मेरे मामले में यह केवल पहली बार होता है जब मैं प्रस्तुति दृश्य नियंत्रक खोलता हूं। @ तो, क्या आप Apple देव मंचों के लिए लिंक प्रदान कर सकते हैं?
AX

जवाबों:


158

मैंने आज उसी मुद्दे का सामना किया है। मैंने इस विषय को खोद लिया है और ऐसा लगता है कि यह मुख्य रनरूप से संबंधित है सो रहा है।

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

इसे ठीक करने के लिए (जब तक कि Apple कुछ न करे) आप कई तरीकों से मुख्य रनअप को ट्रिगर कर सकते हैं:

कॉल करने के लिए कम से कम घुसपैठ समाधान है CFRunLoopWakeUp:

[self presentViewController:vc animated:YES completion:nil];
CFRunLoopWakeUp(CFRunLoopGetCurrent());

या आप एक खाली ब्लॉक को मुख्य कतार में ले जा सकते हैं:

[self presentViewController:vc animated:YES completion:nil];
dispatch_async(dispatch_get_main_queue(), ^{});

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

रुचि रखने वाले किसी व्यक्ति के लिए मैंने रनअप हाइपोथिसिस को सत्यापित करने के लिए मुद्दे की एक न्यूनतम प्रदर्शन परियोजना लिखी: https://github.com/tzahola/pret-bug

मैंने बग को Apple को रिपोर्ट किया है।


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

सेब एक महान गड्ढा खोदता है, मैं इसमें गिरता हूं और बुरी तरह से चोट महसूस करता हूं।
OpenThread

7
OMG, यह बहुत प्रफुल्लित करने वाला है! BTW, यह बग अभी भी मौजूद है।
igrrik

1
मुझे वास्तव में वही समस्या थी जो वास्तव में कष्टप्रद थी, शुक्र है कि इसने इसे ठीक कर दिया।
मार्क

1
पुष्टि की गई कि यह समस्या अभी भी iOS 13 में है
एरिक होरेस्क

69

इस की जाँच करें: https://devforums.apple.com/thread/201431 आप इसे सभी को पढ़ने के लिए नहीं करना चाहते हैं - (मुझे सहित) कुछ लोगों के लिए समाधान बनाने के लिए था presentViewControllerमुख्य थ्रेड पर स्पष्ट रूप से कॉल:

स्विफ्ट 4.2:

DispatchQueue.main.async { 
    self.present(myVC, animated: true, completion: nil)
}

उद्देश्य सी:

dispatch_async(dispatch_get_main_queue(), ^{
    [self presentViewController:myVC animated:YES completion:nil];
});

शायद iOS7 थ्रेड्स में गड़बड़ कर रहा है didSelectRowAtIndexPath


वाह - यह मेरे लिए काम किया। मैं देरी भी देख रहा था। मैं यह नहीं समझ सकता कि यह क्यों आवश्यक होना चाहिए। इसे पोस्ट करने के लिए धन्यवाद।
ड्रुड्रू

4
इस समस्या के बारे में Apple के साथ एक राडार दायर किया: rdar: // 19563577 Openradar.appspot.com/19563577
mluisbrown

1
आईओएस 8 पर इम और यह मेरे लिए इसे ठीक नहीं करता है - यह हमेशा मुख्य धागे पर होने की रिपोर्ट कर रहा है, लेकिन मैं अभी भी वर्णित मुद्दे को देखता हूं।
रॉबर्ट

7

मैंने निम्नलिखित कोड का उपयोग करके इसे स्विफ्ट 3.0 में बाईपास किया:

DispatchQueue.main.async { 
    self.present(UIViewController(), animated: true, completion: nil)
}

1
यह समस्या को हल करता है। मेरे पास एक ही मुद्दा था क्योंकि मैं presentएक बंद कॉलबैक में कॉल कर रहा था ।
जेरेमी पीडीनल

2

[viewController view]प्रस्तुत किए जा रहे व्यू कंट्रोलर को कॉल करके मेरे लिए ट्रिक बनाई।


यह मेरे लिए iOS 8 पर काम करता है। मुझे लगता है कि यह डिस्पैच_संकल्प से बेहतर है।
राबर्ट

0

मैं यह देखने के लिए उत्सुक हूं कि क्या [self setUpViewForNextQuestion];होता है।

आप [self.correctViewController.view setNeedsDisplay];अपने पूर्ण ब्लॉक के अंत में कॉल करने का प्रयास कर सकते हैं presentViewController


अभी, setUpViewForNextQuestion सिर्फ टेबलव्यू पर पुनः लोडडॉट कहता है (यदि कोई गलत अनुमान द्वारा लाल करने के लिए सेट किया गया था, तो सभी पृष्ठभूमि के रंग वापस सफेद करने के लिए)। लेकिन क्या वहाँ किसी भी बदलाव से कोई फर्क पड़ेगा? मुद्दा यह है कि correctViewController तब तक दिखाई नहीं देता है जब तक कि उपयोग फिर से टैप न हो जाए, इसलिए यह समापन ब्लॉक उस दूसरे टैप के बाद तक नहीं बुलाया जा रहा है।
हाफनेमॉर्लड

मैंने आपके सुझाव की कोशिश की, लेकिन इससे कोई फर्क नहीं पड़ा। जैसा कि मैंने कहा, दृश्य दिखाई नहीं दे रहा है, इसलिए दूसरे नल या शेक जेस्चर के बाद पूरा होने वाले ब्लॉक को नहीं बुलाया गया है।
हाफनेमॉर्लड

हम्म। शुरुआत के लिए, मैं इस बात की पुष्टि करने के लिए ब्रेकप्वाइंट का उपयोग करूंगा कि आपके प्रस्तुति कोड को 2 डी टैप तक नहीं कहा जाता है। (बनाम पहले नल पर बुलाया जा रहा है, लेकिन कुछ समय बाद तक ऑनस्क्रीन नहीं खींचा जा रहा है)। यदि उत्तरार्द्ध सत्य है, तो अपनी प्रस्तुति को मुख्य धागे पर होने के लिए मजबूर करें। जब आप "PerformSelectorWithDelay: 0" का उपयोग करते हैं, जो एप्लिकेशन को निष्पादित करने से पहले रन लूप के अगले पुनरावृत्ति तक इंतजार करने के लिए मजबूर करता है। यह थ्रेडिंग-संबंधी हो सकता है।
निक

धन्यवाद, निक। मैं ब्रेकपॉइंट का उपयोग करके कैसे जांच करूंगा? फिलहाल मैं NSLog की जाँच कर रहा हूँ कि प्रत्येक विधि को कब बुलाया जा रहा है। यह मेरे पास अब है: टैप 1 Correct Guess: 1 kHz 18:04:57.173 Frequency[641:60b] [HFBCorrectViewController initWithNibName:bundle:] 18:04:57.177 Frequency[641:60b] [HFBCorrectViewController viewDidLoad] अब कुछ भी नहीं होता है जब तक: टैप 218:05:00.515 Frequency[641:60b] [HFBCorrectViewController viewDidAppear] 18:05:00.516 Frequency[641:60b] Completed Presenting correctViewController 18:05:00.517 Frequency[641:60b] [HFBFrequencyViewController setUpViewForNextQuestion]
हाफ नोर्मलड

क्षमा करें, अधिक स्पष्ट होना चाहिए था। मैं समझता हूं कि ब्रेकपॉइंट का उपयोग कैसे करें। मुझे NSLog जैसी ही कहानी मिलती है। मैंने viewDidLoad और viewDidAppear में सही दृष्टिकोण में ब्रेकप्वाइंट लगाया। यह viewDidLoad पर टूटता है, फिर जब मैं जारी रखता हूं, तो यह बैठता है और दूसरे टैप का इंतजार करता है, फिर viewDidAppear पर टूटता है। कभी-कभी ऐसा लगता है कि इसे नल की आवश्यकता नहीं है और यह समय आधारित है, जब तक मैं चीजों को देख रहा हूं, जो कि दूसरे को बुलाया जा रहा है, के माध्यम से कदम रखा गया है, तो इसे व्यूडीडलड के नाम से जाना जाता है।
हाफ नोर्मलड

0

मैंने UIViewController के लिए विस्तार (श्रेणी) लिखा है जिसमें समस्या हल होती है। कार्यान्वयन के संकेत ( तेज / उद्देश्य-सी ) के लिए AX और NSHipster का धन्यवाद ।

तीव्र

extension UIViewController {

 override public class func initialize() {
    struct DispatchToken {
      static var token: dispatch_once_t = 0
    }
    if self != UIViewController.self {
      return
    }
    dispatch_once(&DispatchToken.token) {
      let originalSelector = Selector("presentViewController:animated:completion:")
      let swizzledSelector = Selector("wrappedPresentViewController:animated:completion:")

      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)
      }
    }
  }

  func wrappedPresentViewController(viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) {
    dispatch_async(dispatch_get_main_queue()) {
      self.wrappedPresentViewController(viewControllerToPresent, animated: flag, completion: completion)
    }
  }
}  

उद्देश्य सी

#import <objc/runtime.h>

@implementation UIViewController (Swizzling)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];

        SEL originalSelector = @selector(presentViewController:animated:completion:);
        SEL swizzledSelector = @selector(wrappedPresentViewController:animated:completion:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        BOOL didAddMethod =
            class_addMethod(class,
                originalSelector,
                method_getImplementation(swizzledMethod),
                method_getTypeEncoding(swizzledMethod));

        if (didAddMethod) {
            class_replaceMethod(class,
                swizzledSelector,
                method_getImplementation(originalMethod),
                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

- (void)wrappedPresentViewController:(UIViewController *)viewControllerToPresent 
                             animated:(BOOL)flag 
                           completion:(void (^ __nullable)(void))completion {
    dispatch_async(dispatch_get_main_queue(),^{
        [self wrappedPresentViewController:viewControllerToPresent
                                  animated:flag 
                                completion:completion];
    });

}

@end

0

जांचें कि क्या स्टोरीबोर्ड में आपके सेल में चयन = कोई नहीं है

यदि हां, तो इसे नीले या भूरे रंग में बदलें और इसे काम करना चाहिए


0

XCode Vesion: 9.4.1, स्विफ्ट 4.1

मेरे मामले में यह तब होता है, जब मैं सेल टैप करता हूं और दूसरे दृश्य के लिए आगे बढ़ता हूं। मैं डीप में डीबग करता हूं और ऐसा लगता है कि viewDidAppearकोड निम्नलिखित होने के कारण अंदर होता है

if let indexPath = tableView.indexPathForSelectedRow {
   tableView.deselectRow(at: indexPath, animated: true)
}

तब मैंने कोड सेगमेंट के अंदर prepare(for segue: UIStoryboardSegue, sender: Any?)और सही काम किया।

मेरे अनुभव के भीतर, मेरा समाधान है, यदि हम किसी दूसरे नए परिवर्तन (जैसे टेबल पुनः लोड, चयन सेल को अचयनित) आदि के लिए उम्मीद करेंगे, जब दूसरे दृष्टिकोण से फिर से आएंगे, तो viewDidAppearउपर्युक्त tableView.deselectRowकोड का उपयोग और उपयोग करने के बजाय प्रतिनिधि का उपयोग करें दूसरे दृश्य नियंत्रक को स्थानांतरित करने से पहले खंड

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