3

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

我首先尝试在根视图控制器的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 完成呈现之前以某种方式呈现模态视图,但我不知道如何解决这个问题。

当应用程序变为活动状态时,我如何“自动”从我的根视图控制器呈现模态视图,并在“正确”时刻执行,以免使我的拆分视图控制器失衡?

4

3 回答 3

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 的视图出现之前呈现模式登录。

以下是不同的场景...

应用程序首次启动:

  • presentModalViewUIApplicationDidBecomeActiveNotification事件调用,但是由于 UISplitViewController 的视图没有加载(并且viewHasAppearedBOOL 为 NO,所以什么也没有发生。赢。我们不应该在不应该的时候呈现视图。
  • 然后最终viewDidAppear被调用,它设置viewHasAppeared为 YES 然后调用presentModalView. 显示登录屏幕。一切都按预期工作-耶!

应用程序在后台后变为活动状态

  • presentModalView和第一个场景一样被UIApplicationDidBecomeActiveNotification事件再次调用,但这次viewHasAppeared是 YES,所以登录视图按预期呈现。耶!

就像我说的,这感觉有点难看,但它可以完成工作,直到我找到更好的解决方案。希望对你有效。

于 2013-04-06T01:58:02.203 回答
0

你试过 UIView 的 viewWillAppear 吗?

于 2012-09-21T15:42:41.173 回答
0

链接@jpolete 的回答,我做了一些不同的事情。此外,我希望登录屏幕仅在应用程序在后台运行超过 15 秒后才出现(用户总是必须重新登录很痛苦)。

这个demo的源码可以在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
于 2014-06-12T19:26:27.997 回答