1. ホーム
  2. ios

[解決済み] presentViewController:animated:YES ビューはユーザーが再度タップするまで表示されない。

2023-02-16 05:48:20

質問

私は presentViewController:animated:completion . 私が作っているものは、基本的に推測ゲームです。

を持っています。 UIViewController (frequencyViewController) を含む UITableView (frequencyTableView)を作成します。ユーザーが正解を含むquestionTableViewの行をタップすると、ビュー(correctViewController)がインスタンス化され、そのビューはモーダルビューとして、画面の下からスライドアップする必要があります。これはユーザーに正しい答えがあることを伝え、次の質問に備えて後ろのfrequencyViewControllerをリセットします。correctViewControllerは、次の質問を表示するためにボタンが押されると解除されます。

これはすべて毎回正しく動作し、correctViewControllerのビューは、以下のように即座に表示されます。 presentViewController:animated:completion がある限り、正しいビューが即座に表示されます。 animated:NO .

もし私が animated:YES を設定すると、correctViewController が初期化され、その中で viewDidLoad . しかし viewWillAppear , viewDidAppear からの補完ブロック、および presentViewController:animated:completion からの完了ブロックは呼び出されません。2回目のタップをするまで、アプリはまだfrequencyViewControllerを表示したままになっています。ここで、viewWillAppear、viewDidAppear、および完了ブロックが呼び出されます。

もう少し調べてみたところ、もう1回タップするだけでは続かないようです。iPhone を傾けたり振ったりすると、viewWillLoad などのトリガーが発生することがあるようです。まるで、他のユーザーからの入力を待っているようです。これは実際の 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];
        }];
    }
}

これが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クリックを取る

そして、もし私が 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];
    }];
}

どのように解決するのですか?

私も今日、同じ問題に遭遇しました。トピックを掘り下げてみたところ、メインのランループがスリープしていることに関係しているようです。

実際、これは非常に微妙なバグで、コード内にわずかなフィードバックアニメーションやタイマーなどがある場合、ランループはこれらのソースによって生かされているため、この問題は表面化しないのです。私は、この問題を 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信号強度の変更など)にも、メインループが起動し、ビューコントローラーが表示されます。

興味のある方のために、私はランループの仮説を検証するために、この問題の最小限のデモ プロジェクトを書きました。 https://github.com/tzahola/present-bug

Apple にもバグを報告しました。