UITableView和presentViewController需要2次点击才能显示

我正在使用UITableView来呈现各种viewControllers。 根据单击的索引,它将显示一个不同的视图控制器,然后可以将其解除。 由于某种原因,我的一个ViewControllers需要两次点击才能显示。 因此,似乎每个其他点击都有效。 其他视图演示工作正常,所以表可能没问题。

我在ViewController中看到的即将显示的是,在第一次单击时,它通过didSelectRowAtIndexPath进行,然后在目标视图中触发:ViewWillLoad,ViewLoaded,ViewWillAppear ….但不是ViewDidAppear。 在第二次单击时,只有ViewDidAppear会在显示时触发。 在第二次单击时,它甚至没有通过didSelectRowAtIndexPath。 此外,我可以第二次点击屏幕上的任意位置,它将显示。

它将继续来回执行此操作,似乎只显示每隔一次点击的目标视图。 有没有想过为什么会这样?

/* RightPanelViewController */ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { switch(indexPath.row){ case 0: // this view takes two clicks to display [self presentViewController:self.delegateRef.savedRidesViewController animated:YES completion:nil]; break; case 1: // this works fine, as do others [self presentViewController:self.delegateRef.sensorsViewController animated:YES completion:nil]; break; case 2: ... } /* savedRidesViewController */ - (void) viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; } - (void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; } 

看看这个: https : //devforums.apple.com/thread/201431如果你不想全部阅读 – 一些人(包括我)的解决方案是在主线程上显式调用presentViewController

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

可能iOS7正在搞乱didSelectRowAtIndexPath的线程。

经过更多的调试,我能够确定它不是视图控制器,而是与didSelectRowAtIndexPath和presentViewController有关。 它开始发生在我所呈现的其他观点上,而且不可靠。 我也尝试使用if / else代替switch而没有帮助。

最终我发现这个解决方案能够修复它,但我不完全确定原因。 通过使用performSelector没有延迟,所有视图立即加载(可能比没有它更快?)并且每次都可靠地加载。

它并不像代码一样干净,但它现在可靠地工作。 我仍然很好奇为什么需要这样做。

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { switch(indexPath.row){ case 0: [self performSelector:@selector(load0:) withObject:nil afterDelay:0]; break; case 1: [self performSelector:@selector(load1:) withObject:nil afterDelay:0]; break; case 2: [self performSelector:@selector(load2:) withObject:nil afterDelay:0]; break; ... } } -(void)load0:(id)sender { [self presentViewController:self.delegateRef.zonesViewController animated:YES completion:nil]; } -(void)load1:(id)sender { [self presentViewController:self.delegateRef.sensorsViewController animated:YES completion:nil]; } -(void)load2:(id)sender { [self presentViewController:self.delegateRef.savedRidesViewController animated:YES completion:nil]; } 

这是presentViewController:animated:completion:一个实际错误presentViewController:animated:completion: 。 请参阅我的答案,并在此处使用正确的解决方法: https : //stackoverflow.com/a/30787046/1812788

在Swift和iOS9中它是:

 dispatch_async(dispatch_get_main_queue(), { self.performSegueWithIdentifier("OpenBookingDetail", sender: self) }) 

斯威夫特3:

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

这种行为的一个原因可能是您的表视图代码,以及启动其他视图控制器的代码,不会在主线程上执行。 但是所有与UI相关的代码都必须在主线程上执行才能正常工作。
因此,请确保代码在主线程上运行,例如通过设置适当的断点。

如前所述,一个修复是明确地在主线程上运行任何视图控制器或使用performSelector

但是 ,我不清楚为什么这是一个修复,因为我的印象是didSelectRow无论如何都在主线程上运行。 直到我读到这个答案 ,事情才变得清晰。

有关详细信息,请阅读链接的答案,但简而言之,这似乎会影响选择样式为none单元格。 这将关闭选择单元格时发生的(默认为灰色)动画,这意味着在调用didSelectRow时不会触发运行循环。 因此,当您去呈现另一个视图控制器时,实际呈现它的动画不会立即出现在运行循环中。

简单地在主线程上运行它的解决方案不是直接修复。 实际上你只需要触发运行循环,比如通过提供一些代码就可以了。 例如:

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

也会解决它。 这具有在呈现视图控制器时触发运行循环的副作用,因此视图控制器的动画现在立即发生。 这也是调用performSelector工作的原因。