在解雇另一个之后立即呈现模态视图控制器

时间:2010-10-12 23:37:32

标签: iphone objective-c uiimagepickercontroller

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

 [self dismissModalViewControllerAnimated:YES];

 UIImagePickerController *picker = [[UIImagePickerController alloc] init];
 picker.delegate = self;
 picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
 [self presentModalViewController:picker animated:YES];

第一个模态VC向下滑动,但新的picker永远不会出现。知道发生了什么事吗?

8 个答案:

答案 0 :(得分:52)

2012年8月更新:

iOS 5及更高版本已经使用完成块将模态动画放入/放出后,为做了更安全的API:

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

2012年8月之前答案:

我在解雇模态1然后快速连续呈现模态2时遇到了类似的问题。有时模态二将在模态一被解雇后显示,有时模态二不会出现,这让我非常难过。

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

对于出现模式2 showModalTwo的方法的调用方放置1秒以上的延迟,每次在模态1被解除后都会出现模态2:

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

这证实了人们怀疑在解雇模式一和提出模式二之间存在某种竞争条件。然而,对呼叫者施加延迟是不够优雅的,并不能保证在其他情况下不会再出现竞争条件。

问题

原来UIViewController有一个公共属性modalViewController,在presentModalViewController:animated:被调用时设置,并在调用dismissModalViewControllerAnimated:时被拆除。问题在于它不会同步被拆除,因此可以在删除modalViewController的旧值和以下列方式设置新值之间创建竞赛。

  1. 目前的模态。 myViewController.modalViewController现在指向模态一
  2. 解雇模式一。拆除myViewController.modalViewController的后台流程已经开始,但myViewController.modalViewController仍然指向模态的
  3. 现在的模态二,myViewController.modalViewController]现在指向模态二
  4. 系统回调触发,将myViewController.modalViewController设置为nil,这会中断模态二动画的过程,结果是用户永远不会看到它。
  5. 比赛从第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. }

    viewDidDisappear:

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

    发布脚本

    我真的不喜欢这个解决方案的轮询方面。 @Nimrod建议,在这个问题的接受答案中,你可以安全地从模态的viewDidDisappear:方法开始提出模态二。我喜欢这种事件驱动方法的声音,但在我的用例中完全实现后,我确认在使用self.modalViewController内的回调呈现模式2时,竞争条件仍然存在。绝对确定将呈现模式2的唯一方法是在父视图控制器内部进行轮询,直到您完全确定nil为{{1}}为止。然后,只有这样才能“安全”弹出模态二。

答案 1 :(得分:16)

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

答案 2 :(得分:14)

[self dismissViewControllerAnimated:YES completion:^{
    //Present the new MVC 

}];

注意:iOS 5.0以上版本。

答案 3 :(得分:5)

[self dismissModalViewControllerAnimated:NO];

 UIImagePickerController *picker = [[UIImagePickerController alloc] init];
 picker.delegate = self;
 picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
 [self presentModalViewController:picker animated:YES];

答案 4 :(得分:2)

发生的事情是视图控制器在完成解除动画后删除它对模态视图控制器的引用,这在调用此代码后发生,因此它不认为它有一个新的视图控制器来模态呈现。 / p>

我如何处理此问题是在致电didDismissModalVC后将YES ivar设为dismissModalViewController。然后在我的viewDidAppear:方法中,检查ivar的值,然后显示新的模态视图控制器。 (还记得将值设置回NO,这样我就不会被永远地解雇模态视图控制器。)

答案 5 :(得分:0)

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

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

@protocol ParentViewControllerDelegate
- (void)showModalTwo;
@end

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

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

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

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

希望得到这个帮助。

答案 6 :(得分:0)

在斯威夫特:

  1. 使用dismissViewController关闭第一个呈现的视图。
  2. 使用dismissViewController的completion block来调用mainVC中的函数。该函数应调用第二个VC。
  3. 你的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所在的场所是其他的VC:

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

答案 7 :(得分:0)

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

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

   view.isHidden = true

然后,在它的viewWillAppear上,显示模态viewController,在完成时启用并取消隐藏视图:

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

您可能希望使用Bool来控制您的州,以便后续拨打viewWillAppear不会重新呈现该模式,但您明白了。