应用程序变为活动状态时显示模态视图

时间:2012-09-21 15:40:57

标签: ios ipad

我希望在我的应用启动时呈现模态视图控制器(用于登录屏幕),以及在用户点击主页按钮然后重新启动应用后再次变为活动状态时。

我首先尝试在根视图控制器的viewDidAppear:方法中呈现模态视图。应用程序首次启动时效果很好,但是当应用再次变为活动状态时,不会调用此方法。

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self presentModalView];
}

- (void)presentModalView {
    if(![AuthenticationService sharedInstance].isAuthenticated) {
        _modalVC = [self.storyboard instantiateViewControllerWithIdentifier:self.modalViewControllerIdentifier];
        _modalVC.delegate = self;
        [self presentViewController:_modalVC animated:YES completion:nil];
    }
}

接下来,我尝试使用applicationDidBecomeActive:方法从我的应用代理中调用此内容。

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.

    ModalPresentingUISplitViewController *splitViewController = (ModalPresentingUISplitViewController *)self.window.rootViewController;
    [splitViewController presentModalView];
}

这似乎在表面上工作正常,但我在日志中收到Unbalanced calls to begin/end appearance transitions for <ModalPresentingUISplitViewController: 0x7251590>警告。我觉得我在UISplitView完成呈现之前会以某种方式呈现模态视图,但我不知道如何解决这个问题。

当应用程序变为活动状态时,如何从根视图控制器“自动”显示模态视图,并在“正确”时刻执行此操作,以免不平衡我的分割视图控制器?

3 个答案:

答案 0 :(得分:1)

忘了这个问题在这里。是的,我有一个解决方案。我不禁觉得有更优雅或正确的方式来做到这一点,但这对我有用......

这假设您使用ARC和故事板;您已经为登录视图创建了一个UIViewController,其中包含来自UISplitViewController的模态segue(或者您的根视图控制器)。

UISplitViewController(或任何你的根视图控制器)

- (id)initWithCoder:(NSCoder *)aDecoder {
    if(self = [super initWithCoder:aDecoder]) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(presentModalView) name:UIApplicationDidBecomeActiveNotification object:nil];
    }
    return self;
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}

- (void) viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    self.viewHasAppeared = YES;
    [self presentModalView];
}

- (void) presentModalView {
    if(self.viewHasAppeared && !self.userAuthenticated) {
        [self performSegueWithIdentifier:@"ShowLoginView" sender:self];
    }
}

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if([[segue identifier] isEqualToString:@"ShowLoginView"]) {
        JDPLoginViewController *dest = [segue destinationViewController];
        dest.delegate = self;
    }
}

- (void) dismissLogin {
    self.userAuthenticated = YES;
    [self dismissViewControllerAnimated:YES completion:nil];
}

以下是要注意的代码的重要部分......

  1. 我们正在调用presentModalView两个地方 - viewDidAppear,这将在应用首次启动时显示我们的登录视图,并且
  2. 我们正在注册presentModalView作为UIApplicationDidBecomeActiveNotification事件的观察者,因此当应用程序在后台运行后变为活动状态时会调用该方法。
  3. 最后,我们在UISplitViewController上创建一个BOOL属性viewHasAppeared,以跟踪UISplitViewController的视图是否出现,因此我们不会尝试在UISplitViewController的视图出现之前呈现模态登录。
  4. 以下是不同的方案......

    App First Starts:

      {li> presentModalViewUIApplicationDidBecomeActiveNotification事件调用,但由于未加载UISplitViewController的视图(并且viewHasAppeared BOOL为NO,因此没有任何反应.Win。我们不存在我们不应该这样看。
    • 然后最终调用viewDidAppear,将viewHasAppeared设置为YES,然后调用presentModalView。出现登录屏幕。一切都按预期工作 - 耶!

    应用程序在后台运行后变为活动

      {li> presentModalViewUIApplicationDidBecomeActiveNotification事件再次调用,如第一个场景中所示,但这次viewHasAppeared为YES,因此登录视图按预期显示。再说一遍!

    就像我说的那样,这感觉很难看,但是直到找到更好的解决方案才能完成工作。希望它适合你。

答案 1 :(得分:0)

您是否尝试过UIView的viewWillAppear?

答案 2 :(得分:0)

关闭@ jpolete的答案我做的事情有点不同。此外,我希望登录屏幕仅在应用程序在后台运行15秒后才会显示(用户始终必须重新登录才会感到痛苦)。

此演示的源代码可在github

上找到

与@jpolete一样,我将大部分逻辑封装在根视图控制器中,在我的情况下是一个导航控制器(iPhone示例)。 userLoggedIn标记用户是否已经过身份验证。 presentingLoginController标志让我知道当前是否显示登录屏幕。 backgroundTime包含用户进入后台时的时间戳。这是类扩展:

@interface RootNavigationController () <LoginDelegate>
@property (assign, nonatomic) BOOL userLoggedIn;
@property (strong, nonatomic) NSDate *backgroundTime;
@property (assign, nonatomic) BOOL presentingLoginController;
-(void)applicationDidBecomeActive:(NSNotification*) notification;
-(void)applicationDidEnterBackground:(NSNotification*) notification;
@end

加载视图后,我添加了相应的通知挂钩:

@implementation RootNavigationController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidBecomeActive:)
                                                 name:UIApplicationDidBecomeActiveNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(applicationDidEnterBackground:)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil];
}

-(void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

如果用户未经过身份验证且我们当前未提供登录控制器,则会触发登录segue。

-(void)loginIfNecessary {
    if (!self.userLoggedIn && !self.presentingLoginController) {
        self.presentingLoginController = YES;
        [self performSegueWithIdentifier:@"RootLoginSegue" sender:self];
    }
}

这里我们将根视图控制器设置为登录控制器的loginDelegate。 成功登录时会通知此代理(登录控制器嵌入在另一个导航控制器中):

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:@"RootLoginSegue"]) {
        UINavigationController *navController = segue.destinationViewController;
        LoginTableViewController *loginController = (LoginTableViewController *) navController.topViewController;
        loginController.loginDelegate = self;
    }
}

成功登录后,我们会执行以下操作:

-(void)didLogin { // LoginDelegate method called to login controller after successsful login
    self.presentingLoginController = NO;
    self.userLoggedIn = YES;
}

当视图第一次出现时,当它出现在后台后,或者在被“掩盖”后,我们登录(如果需要):

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self loginIfNecessary];
}

当我们进入背景时,我们记录时间:

-(void)applicationDidEnterBackground:(NSNotification*) notification {
    self.backgroundTime = [NSDate date];
}

当我们进入前景并且它第一次或足够的时间过去了然后我们 强制用户再次登录(如有必要):

-(void) applicationDidBecomeActive:(NSNotification*) notification {
    const NSTimeInterval maxBackgroundTime = 15.0;
    if (!self.backgroundTime || [[NSDate date] timeIntervalSinceDate:self.backgroundTime] > maxBackgroundTime) {
        self.userLoggedIn = NO;
    }
    [self loginIfNecessary];
}

@end