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

我有一个包含UIViewController(frequencyTableView)的UITableView(frequencyViewController)。当用户点击问题表 View 中包含正确答案的行时,应实例化一个 View (correctViewController),并且其 View 应从屏幕底部作为模态视图向上滑动。这告诉用户他们的答案正确,并且将其后面的frequencyViewController重置为下一个问题做好了准备。按下按钮以显示下一个问题时,会关闭correctViewController。

每次都可以正常运行,只要presentViewController:animated:completion具有animated:NO,即可立即显示正确的ViewController的 View 。

如果设置了animated:YES,则会初始化correctViewController并调用viewDidLoad。但是,不会调用viewWillAppearviewDidAppearpresentViewController:animated:completion中的完成块。该应用程序只是坐在那里,仍然显示frequencyViewController,直到我再次点击为止。现在,将调用viewWillAppear,viewDidAppear和完成块。

我进行了更多调查,不仅仅是让它继续下去的另一个水龙头。看来,如果我倾斜或摇动我的iPhone,这也可能导致它触发viewWillLoad等。这就像它在等待用户输入的其他任何内容之前,都将继续进行。这是在真实的iPhone和模拟器上发生的,我通过将摇指令发送到模拟器来证明这一点。

我真的对此无所适从……我非常感谢任何人都可以提供的任何帮助。

谢谢

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

这是questionViewController中的代码,充当questionTableView的委托(delegate)

- (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 and presentViewController takes 2 clicks to display

而且,如果我将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];
    }];
}

最佳答案

我今天也遇到了同样的问题。我研究了这个主题,似乎它与主运行循环处于 sleep 状态有关。

实际上,这是一个非常微妙的错误,因为如果您的代码中包含最少的反馈动画,计时器等,则此问题将不会浮出水面,因为这些源将使runloop保持 Activity 状态。我通过使用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(), ^{});

这很有趣,但是如果您摇晃设备,它也会触发主循环(它必须处理运动事件)。与水龙头相同,但包含在原始问题中:)此外,如果系统更新状态栏(例如时钟更新,WiFi信号强度更改等),这也将唤醒主循环并显示 View Controller 。

对于感兴趣的任何人,我都编写了一个有关该问题的最小演示项目,以验证运行循环假设:https://github.com/tzahola/present-bug

我也已将该错误报告给了Apple。

10-02 07:17
查看更多