【问题标题】:Presenting a modal view controller immediately after dismissing another关闭另一个模态视图控制器后立即呈现
【发布时间】:2011-04-24 14:33:37
【问题描述】:

我正在关闭一个模态视图控制器,然后立即呈现另一个,但后者永远不会发生。代码如下:

[自我dismissModalViewControllerAnimated:是]; UIImagePickerController *picker = [[UIImagePickerController alloc] init]; 选择器.delegate = self; picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; [self presentModalViewController:picker animated:YES];

第一个模态 VC 向下滑动,但新的 picker 从未出现。知道发生了什么吗?

【问题讨论】:

  • 创建新的UIImagePickerController实例不是个好主意,你能用旧的吗?
  • 你能扩展一下吗?为什么这是个坏主意?

标签: iphone objective-c uiimagepickercontroller


【解决方案1】:

2012 年 8 月更新:

iOS 5 及更高版本引入了更安全的 API 来处理模态使用完成块动画进入/退出位置:

[self presentViewController:myModalVC animated:YES completion:^{}];
[self dismissViewControllerAnimated:YES completion:^{}];

2012 年 8 月之前的答案:

我在关闭模态一然后快速连续呈现模态二时遇到了类似的问题。有时候情态二会在情态一被解散后显示,有时候情态二根本不会出现,这让我很伤心。

对我来说看起来像是一种竞争条件......

在显示模态二 showModalTwo 的方法的调用者上放置 1 秒以上的延迟,使模态二在模态一被解除后每次出现:

- (void)didDismissModalOne {
    [self performSelector:@selector(showModalTwo:) 
               withObject:someNumber 
               afterDelay:1.0f];
}

这证实了一种怀疑,即在模态一的解雇和模态二的呈现之间存在某种竞争条件。然而,延迟调用者是不雅的,并且不能保证竞争条件在其他情况下不会再次出现。

问题

原来UIViewControllers 有一个公共属性modalViewController,它在presentModalViewController:animated: 被调用时被设置,在dismissModalViewControllerAnimated: 被调用时被拆除。问题是它不会被同步拆除,因此可能会在删除 modalViewController 的旧值和通过以下方式设置新值之间产生竞争。

  1. 当前模式一。 myViewController.modalViewController 现在指向模态一
  2. 关闭模式一。后台进程拆除myViewController.modalViewController已经开始,但myViewController.modalViewController仍然指向模态一
  3. 当前模态二,myViewController.modalViewController] 现在指向模态二
  4. 系统回调触发,将myViewController.modalViewController设置为nil,这会中断模态二动画的过程,结果是用户永远看不到它。

比赛从第 2 步开始,在第 4 步显现。

解决方案

我的解决方案是在呈现模态二的方法上设置一个保护条件,以确保在尝试呈现模态二之前 myViewControoler.modalViewControllernil

-(void)showModalTwo:(NSNumber *)aParameter {

    if (self.modalViewController) {        
            [self performSelector:@selector(showModalTwo:)
                       withObject:aParameter 
                       afterDelay:0.1f];
            return;
    }
    // You can now present the second modal safely.
}

工作就像一个魅力。更优雅的解决方案可能包括超时。

发布脚本

我真的不喜欢这个解决方案的轮询方面。 @Nimrod 建议,在这个问题的公认答案中,您可以从模态一的 viewDidDisappear: 方法安全地启动模态二的呈现。我喜欢这种事件驱动方法的声音,但是在我的用例中进行了完整的实现之后,我确认在使用viewDidDisappear: 中的回调呈现模态二时,竞争条件仍然存在。绝对确定将呈现模态二的唯一方法是在父视图控制器中进行轮询,直到您完全确定 self.modalViewControllernil。只有这样,弹出模态二才“安全”。

【讨论】:

  • +1 可爱优雅的解决方案;特别喜欢学习 performSelector 方法……每天都学点新东西:-D
  • 对于那些想知道为什么使用 iOS 5.0+ 解决方案会收到 method not found 错误的人,请注意 dismissModalViewControllerAnimated...dismissViewControllerAnimated... 之间的区别(Modal 现在已经消失了)。容易犯掌脸错误。
  • @prairiedogg ,想知道我应该为 "someNumber" 传递什么?我有一些问题,如果你有时间,我希望你不介意在这里访问我关于类似问题的问题stackoverflow.com/questions/15893817/…
  • 使用dismissViewControllerAnimated:YES completion:^{[self.delegate show2ndVC];} 为我工作。
【解决方案2】:

像其他动画一样,dismissModalViewControllerAnimated 在视图控制器消失之前不会阻塞。相反,它“开始”解雇视图控制器。您可能需要在模态控制器 1 的 viewDidDisappear 中使用回调,该回调在父视图控制器中调用类似 modalViewControllerDisappeared 的内容。在该方法中,您将呈现模态控制器 2。否则机器人 K 所说的。

【讨论】:

  • 这是个好主意。下次我必须这样做时,我可能会尝试一下。
  • 不确定它会起作用(我没有测试过),但它似乎应该。
  • 我尝试使用此答案中推荐的事件驱动方法,将回调放在viewDidDisappear 中,并且竞争条件持续存在。请参阅我对这个问题的回答,了解最终对我有用的解决方案。
【解决方案3】:
[self dismissViewControllerAnimated:YES completion:^{
    //Present the new MVC 

}];

注意:iOS 5.0 以上版本可用。

【讨论】:

    【解决方案4】:
    [self dismissModalViewControllerAnimated:NO];
    
     UIImagePickerController *picker = [[UIImagePickerController alloc] init];
     picker.delegate = self;
     picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
     [self presentModalViewController:picker animated:YES];
    

    【讨论】:

    • 将动画设置为 NO 以关闭它。
    • 我认为这段代码行不通。 dismissModalViewControllerAnimated 将释放您在 VC 中的所有内容,然后您尝试在此 VC 上呈现另一个视图控制器
    • 我希望您知道,来自视图控制器的上述调用不会自行关闭。但是它当前作为模态呈现的视图控制器。由于您的评论是错误的,因此不需要投票。无意冒犯,但在这里我必须直言不讳。干杯。
    • 另外,IronLeash,我希望你知道我的答案是在 iOS5 之前的 2010 年发布的。您发布的解决方案可从 iOS 5 开始使用....请考虑到这一点。
    • 我在 VC 中尝试过它,它只是崩溃了。我想在关闭视图控制器后调用委托方法
    【解决方案5】:

    发生的情况是视图控制器在关闭动画完成后删除它对模态视图控制器的引用,这发生在调用此代码之后,因此它认为它没有新的视图控制器来模态呈现。

    我的处理方法是在调用dismissModalViewController 后将didDismissModalVC ivar 设置为YES。然后在我的viewDidAppear: 方法中,我检查 ivar 的值并呈现新的模态视图控制器。 (记住还要将值设置回NO,这样我就不会永远被模式视图控制器卡住。)

    【讨论】:

      【解决方案6】:

      在这种情况下,我创建了回调父视图控制器的委托以显示第二个模式视图控制器。

      父视图控制器的定义协议:

      @protocol ParentViewControllerDelegate
      - (void)showModalTwo;
      @end
      

      我在父视图控制器中实现此协议以显示第二个模态视图控制器并在第一个模态视图控制器上创建委托属性@property id<ParentViewControllerDelegate> delegate;

      从父视图控制器显示第一个模态视图控制器:

      TheFirstModalViewController *controller = ...
      controller.delegate = self;
      [self presentViewController:controller animated:YES completion:nil];
      ...
      

      在第一个模态视图控制器的viewDidDisappear: 方法上,只需调用delegate.showModalTwo: 即可从父视图控制器显示第二个模态视图。

      希望对您有所帮助。

      【讨论】:

        【解决方案7】:

        在斯威夫特中:

        1. 使用dismissViewController 关闭第一个呈现的视图。
        2. 使用dismissViewController 的completion block 调用mainVC 中的函数。该函数应该调用第二个 VC。

        您的dismissViewController 应该如下所示:

        var presentingVC_Delegate: mainLists_PopoverDelegation!
        
        @IBAction fund button_Pressed (sender: AnyObject) {
            self.dismissViewControllerAnimated(true, completion: { finished in
                self.presentingVC_Delegate.presentOtherVC()
                print("DismissVC completion block says hello")
            })
        }
        

        mainVC 在哪里展示OtherVC:

        func presentSettingsVC () {
            self.performSegueWithIdentifier("present_OtherVC", sender: nil)
        }
        

        【讨论】:

          【解决方案8】:

          这是我的方法,似乎在 iOS 10 上运行良好。我的情况略有不同,但应该适用于大多数情况。我将初始 viewController 呈现为弹出框,需要立即呈现模态 viewController。

          首先,在初始 viewController 的 viewDidLoad 中隐藏它的视图:

             view.isHidden = true
          

          然后,在 viewWillAppear 上,呈现模态视图控制器,取消动画并在完成时取消隐藏视图:

             present(yourModalViewController, animated: false) { [unowned self]
                 self.view.isHidden = false
              }
          

          您可能希望使用 Bool 来控制您的状态,以便随后对 viewWillAppear 的调用不会重新呈现模式,但您明白了。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-02-03
            • 2014-09-16
            • 1970-01-01
            • 2014-12-12
            • 1970-01-01
            相关资源
            最近更新 更多