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

时间:2013-12-02 03:59:38

标签: ios objective-c uitableview

我正在使用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];
}

8 个答案:

答案 0 :(得分:55)

检查一下:https://devforums.apple.com/thread/201431 如果您不想全部阅读 - 某些人(包括我)的解决方案是在主线程上明确地进行presentViewController调用:

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

可能iOS7正在弄乱didSelectRowAtIndexPath中的线程。

答案 1 :(得分:6)

经过更多调试后,我能够确定它不是视图控制器,而是与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];
}

答案 2 :(得分:4)

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

答案 3 :(得分:3)

斯威夫特3:

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

答案 4 :(得分:2)

在Swift和iOS9中,它是:

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

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

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

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

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

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

答案 7 :(得分:0)

didSelectRow方法的末尾,取消选择它,以便下次可以选择它。

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
 .
 .
 .
 tableView.deselectRow(at: indexPath, animated: false)
}