莫代尔瞄准链

时间:2012-12-05 17:01:07

标签: ios modal-dialog segue viewcontroller

我有一个iOS应用程序,它具有登录视图(LognnViewController),一旦用户成功通过身份验证,就会转到另一个视图(DetailEntryViewController)以输入一些简单的详细信息。
输入详细信息后,用户将进入应用程序的主要部分,该部分由包含各种其他视图的选项卡控制器(TabViewController)组成。 LogInViewController对DetailEntryViewController执行模态segue,DetailEntryViewController然后对TabViewController执行模态segue,所以我有一种模态segue链进入应用程序。当用户注销时,我想一直回到LogInViewController,但当我这样做时:

[self.presentingViewController dismissModalViewControllerAnimated:YES];

...它弹出TabViewController,我最终返回DetailEntryViewController而不是第一个LogInViewController。有没有什么方法可以轻松地回到第一个视图控制器或做这个模态segue链的事情阻止我。我明智地想在DetailEntryViewController viewWillAppear中添加一些代码:如果用户已经注销,它会自动弹出,但viewWillAppear中不允许调用解雇模态控制器}:viewDidLoad:等等

关于如何实现这一目标的任何想法?

4 个答案:

答案 0 :(得分:8)

我认为这不是实施应用的最佳结构。模态控制器应该用于暂时中断程序流程,因此使用模态来获取主要内容并不理想。我这样做的方法是让你的标签栏控制器成为窗口的根视图控制器,然后在第一个标签的控制器中,从viewDidAppear方法以模态方式显示登录控制器,这样它就会立即出现(你会看到它)除非取消选中segue属性检查器中的“动画”框,否则将显示第一个选项卡的视图。显示那个细节控制器,然后关闭两个模态控制器以返回到您的主要内容。当用户注销时,只需再次显示该登录控制器。我像这样实现这个想法。在第一个选项卡的视图控制器中:

- (void)viewDidLoad {
    [super viewDidLoad];
    _appStarting = YES;
}

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if (_appStarting) {
       [self performSegueWithIdentifier:@"Login" sender:self];
        _appStarting = NO;
    }
}

然后在最后一个(在你的情况下为第二个)模态视图控制器中,我有一个按钮方法:

-(IBAction)goBackToMain:(id)sender {
    [self.view.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
}

答案 1 :(得分:1)

自己搞清楚......只需要再上一层就可以到达“root”视图控制器(LogInViewController),发现这就行了:

[[self.presentingViewController presentingViewController] dismissViewControllerAnimated:YES completion:nil];

正如我所说,我只是获取了presentationViewController(DetailEntryViewController),然后又上升了一个级别并获得该控制器的演示者(LogInViewController)。

答案 2 :(得分:1)

我有类似的问题,我的“模态segue链”不受限制。我同意下面关于为不同事物设计的模态segue的答案和评论中的论点,但我喜欢模态segues的“水平翻转”动画,我找不到更容易的方法来复制它们...另外一般我在使用为一件事物设计的东西来实现其他一些东西时看不出有什么不妥,比如链接模态控制器。重复的“部分卷曲”动画也适用于某些应用中的某些场景。

所以我将模态控制器的堆栈实现为控制器的属性:

@interface ModalViewController : UIViewController
@property (nonatomic, retain) NSMutableArray *modalControllers;
@end

当执行第一个模态segue时,堆栈是在非模态控制器的prepareForSegue方法中创建的:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"modalSegue"]) {
        ModalViewController *controller =
            (ModalViewController *)[segue destinationViewController];

        controller.modalControllers = [NSMutableArray arrayWithObject: controller];
    }
}

当一个模态控制器移动到另一个模态控制器时,目标被添加到堆栈中(在ModalViewCotroller的方法中)

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"modalSegue"]) {
        ModalViewController *destController =
            (ModalViewController *)[segue destinationViewController];

        // add destination controller to stack
        destController.modalControllers = _modalControllers;
        [destController.modalControllers addObject: destController];
    }
}

立刻解散整个堆栈是最棘手的部分 - 你不能在下一次完成解雇之前解除之前的控制器,所以循环不起作用,只有递归块才能解决问题,避免内存泄漏最棘手的(我还没检查,但我依靠this):

- (IBAction)dismissAllModalControllers: (id)sender
{
    // recursive block that dismisses one auth controller
    // all these dances are to avoid leaks with ARC
    typedef void (^voidBlockType)();
    __block void (^dismissController) ();
    voidBlockType __weak dismissCopy = ^void(void) {
        dismissController();
    };
    dismissController = ^void(void) {
        int count = [_modalControllers count];
        if (count > 0) {
            // get last controller
            UIViewController *controller =
                (UIViewController *)[_modalControllers lastObject];
            // remove last controller
            [_modalControllers removeLastObject];
            // dismiss last controller
            [controller
                // the first controller in chain is dismissed with animation
                dismissViewControllerAnimated: count == 1 ? YES : NO
                // on completion call the block that calls this block recursively
                completion: dismissCopy]; 
        }
    };

    // this call dismisses all modal controllers
    dismissController();        
}

答案 3 :(得分:0)

[self.navigationController popToRootViewControllerAnimated:YES];