presentViewController:animated:YES 视图不会出现,直到用户再次点击 [英] presentViewController:animated:YES view will not appear until user taps again

查看:26
本文介绍了presentViewController:animated:YES 视图不会出现,直到用户再次点击的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

presentViewController:animated:completion 出现了一些奇怪的行为.我所做的本质上是一个猜谜游戏.

I'm getting some strange behaviour with presentViewController:animated:completion. What I'm making is essentially a guessing game.

我有一个 UIViewController (frequencyViewController) 包含一个 UITableView (frequencyTableView).当用户点击 questionTableView 中包含正确答案的行时,应该实例化一个视图 (correctViewController) 并且它的视图应该从屏幕底部向上滑动,作为一个模态视图.这告诉用户他们有一个正确的答案并重置它后面的 frequencyViewController 为下一个问题做好准备.rightViewController 在按下按钮时被解除以显示下一个问题.

I have a UIViewController (frequencyViewController) containing a UITableView (frequencyTableView). When the user taps on the row in questionTableView containing the correct answer, a view (correctViewController) should be instantiate and its view should slide up from the bottom of the screen, as a modal view. This tells the user they have a correct answer and resets the frequencyViewController behind it ready for the next question. correctViewController is dismissed on a button press to reveal the next question.

这一切每次都正常工作,并且只要 presentViewController:animated:completionanimated:NO,就会立即出现正确的ViewController 视图.

This all works correctly every time, and the correctViewController's view appear instantly as long as presentViewController:animated:completion has animated:NO.

如果我设置了animated:YES,则正确的ViewController 会被初始化并调用viewDidLoad.但是 viewWillAppearviewDidAppear 和来自 presentViewController:animated:completion 的完成块没有被调用.该应用程序只是坐在那里仍然显示 frequencyViewController 直到我再次点击.现在,viewWillAppear、viewDidAppear 和完成块被调用.

If I set animated:YES, correctViewController is initialized and makes calls to viewDidLoad. However viewWillAppear, viewDidAppear, and the completion block from presentViewController:animated:completion are not called. The app just sits there still showing frequencyViewController until I make a second tap. Now, viewWillAppear, viewDidAppear and the completion block are called.

我进行了更多调查,这不仅仅是另一个点击会导致它继续.似乎如果我倾斜或摇晃我的 iPhone,这也会导致它触发 viewWillLoad 等.这就像它在继续之前等待任何其他用户输入一样.这发生在真实的 iPhone 和模拟器中,我通过向模拟器发送抖动命令来证明这一点.

I investigated a bit more, and it's not just another tap that will cause it to continue. It seems if I tilt or shake my iPhone this can also cause it to trigger the viewWillLoad etc. It's like it's waiting to any other bit of user input before it will progress. This happens on a real iPhone and in the simulator, which I proved by sending the shake command to the simulator.

我真的不知道该怎么办...我真的很感激任何人可以提供的任何帮助.

I'm really at a loss as to what to do about this... I'd really appreciate any help anyone can provide.

谢谢

这是我的代码.很简单...

Here's my code. It's pretty simple...

这是 questionViewController 中的代码,它充当 questionTableView 的委托

This is code in questionViewController that acts as the delegate to the 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

This is the whole of the correctViewController

@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次点击显示

I found this question earlier: UITableView and presentViewController takes 2 clicks to display

如果我将我的 didSelectRow 代码更改为这个,它可以很长时间地与动画一起工作......但是它很混乱,并且对于为什么它首先不起作用没有意义.所以我不认为这是一个答案...

And if I change my didSelectRow code to this, it works very time with animation... But it's messy and doesn't make sense as to why it doesn't work in the first place. So I don't count that as an answer...

- (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];
    }];
}

推荐答案

我今天遇到了同样的问题.我深入研究了这个话题,它似乎与主 runloop 处于睡眠状态有关.

I've encountered the same issue today. I dug into the topic and it seems that it's related to the main runloop being asleep.

实际上,这是一个非常微妙的错误,因为如果您的代码中有最轻微的反馈动画、计时器等,这个问题就不会出现,因为这些源会保持 runloop 处于活动状态.我通过使用 UITableViewCell 发现了这个问题,它的 selectionStyle 设置为 UITableViewCellSelectionStyleNone,所以没有选择动画在行之后触发 runloop选择处理程序运行.

Actually it's a very subtle bug, because if you have the slightest feedback animation, timers, etc. in your code this issue won't surface because the runloop will be kept alive by these sources. I've found the issue by using a UITableViewCell which had its selectionStyle set to UITableViewCellSelectionStyleNone, so that no selection animation triggered the runloop after the row selection handler ran.

要修复它(直到 Apple 做某事),您可以通过多种方式触发主运行循环:

To fix it (until Apple does something) you can trigger the main runloop by several means:

干扰最小的解决方案是调用CFRunLoopWakeUp:

The least intrusive solution is to call CFRunLoopWakeUp:

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

或者你可以将一个空块加入主队列:

Or you can enqueue an empty block to the main queue:

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

这很有趣,但如果你摇动设备,它也会触发主循环(它必须处理运动事件).与水龙头相同的事情,但这包含在原始问题中:) 此外,如果系统更新状态栏(例如时钟更新、WiFi 信号强度变化等),它也会唤醒主循环并呈现视图控制器.

It's funny, but if you shake the device, it'll also trigger the main loop (it has to process the motion events). Same thing with taps, but that's included in the original question :) Also, if the system updates the status bar (e.g. the clock updates, the WiFi signal strength changes etc.) that'll also wake up the main loop and present the view controller.

对于任何有兴趣的人,我写了一个该问题的最小演示项目来验证 runloop 假设:https://github.com/tzahola/present-bug

For anyone interested I wrote a minimal demonstration project of the issue to verify the runloop hypothesis: https://github.com/tzahola/present-bug

我也向 Apple 报告了这个错误.

I've also reported the bug to Apple.

这篇关于presentViewController:animated:YES 视图不会出现,直到用户再次点击的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆