3

What is the best way to display a view (in my case a login screen) on app resume. From looking around, I've been playing with the applicationDidBecomeActive event in my AppDelegate, but I cannot seem to get my head around how to properly display a view from here.

I've tried to grab the current window by using self.window and/or it's subviews, but from the AppDelegate self.window is nil.

So far this application seems to be wired up correctly, but I am baffled by two things.

A) why is self.window nil from within my AppDelegate's applicationDidBecomeActive event handler.

B) what is the correct/normal way of display a login view (or the like) on application resume.

Jason Whitehorn
  • 13,585
  • 9
  • 54
  • 68
  • Maybe rethink this. Do you really want to display the login because the app resumed? Or do you want to display the login because it is required to see the current view? I check on every viewWillAppear if the user is logged in. If not, I display a modal login view. That kinda covers everything without having to worry about if the app just resumed or not. – Steven Stefanik Jan 25 '12 at 21:05
  • http://stackoverflow.com/questions/6622762/splash-screen-on-resume-in-iphone – Steven Stefanik Jan 25 '12 at 21:07
  • Did you try something like this `[self.rootViewController presentModalViewController:loginController];`? – Roman Temchenko Jan 25 '12 at 21:14
  • @StevenStefanik, a login will be required for the entire app. I guess I could have all my controller's inherent from a base controller, and implement logic in the `viewWillAppear` handler, but it just seemed like the AppDelegate was the place for this... am I wrong? – Jason Whitehorn Jan 25 '12 at 21:25
  • @RomanTemchenko, AppDelegate does not have a rootViewController property. There is a self.window.rootViewController, but, again, self.window is nil. – Jason Whitehorn Jan 25 '12 at 21:26
  • Are you sure your code in applicationDidBecomeActive executed? Put an NSLog in there to make sure. – Steven Stefanik Jan 25 '12 at 21:33
  • I did, and it was... i even set a break point in it to be certain. I am currently playing around with using a subtype of UIViewController as the parent type for all my controllers (e.g., the idea you gave me)... so far, I'm having good success with this... Perhaps you could sum that up as an answer ;-) – Jason Whitehorn Jan 25 '12 at 21:39
  • `self.keyWindow` is it nil too??? It should have `rootViewCOntrolelr` property you need. – Roman Temchenko Jan 25 '12 at 21:46

3 Answers3

4

Implement a custom UIViewController for all of your applications to inherent from. In this view controller implement logic in the viewWillAppear message to determine and show the login screen if necessary.

//CustomViewController.h
@interface CustomViewController : UIViewController
@end

//CustomerViewController.m
@implementation CustomViewController
-(void)viewWillAppear:(BOOL)animated{
    if(login_required){
         LoginViewController *loginView = [[LoginViewController alloc] initWithNibName:@"LoginView" bundle:nil];
         [self presentModalViewController:loginView animated:false];
    }
}
@end

Then, simply, in your login view controller make sure you call:

[self dismissModalViewControllerAnimated:false];

The benefits of this approach are two fold. Firstly, it's a very simple implementation. However, most compellingly, having a base class for an application's view controller presents the opportunity to extract common logic.

Jason Whitehorn
  • 13,585
  • 9
  • 54
  • 68
  • This solution was primally inspired by a comment from Steven Stefanik. I had encouraged him to post this as a formal answer, but he did not. @StevenStefanik if you want to take credit I'll gladly remove my answer and accept yours. Until then, I feel that this is the correct answer. Thank you for your help! – Jason Whitehorn Jan 26 '12 at 14:50
  • What would you suggest doing if your classes inherit from UITableViewControllers... not just UIViewController? – Ian May 20 '12 at 19:33
2

Jason,

I have worked on a security tutorial provided by Chris Lowe on raywenderlich.com that was intended to demonstrate how to use basic iOS security to lock the application.

The premise behind this tutorial though was that the application would prompt for login upon first launch and if application was resumed upon unlocking the device through the use of NSNoftificationCenter in viewDidLoad and subscribe the the notifications: deviceWillLock and deviceWillUnlock. All of this assumes the device is set to lock.

Basic iOS Security Tutorial Part 2 - This is the part that has the NSNotification registration.

Basic iOS Security Tutorial Part 1 - This is the first part of the tutorial for clarity.

Ethan Mateja
  • 201
  • 2
  • 9
1

I also ran into this problem and came across this question whilst researching a solution. I didn't want to create the intermediate super class for my views and I wasn't sure how it would work out with navigation controllers. I have come up with another solution that works well for me - so thought I would share it. It is based around the use of NSNotificationCenter .

In your app delegate create a property to hold a reference to the currently displayed view controller - say currentViewController.

Then in the applicationDidFinishLaunching method, register a block observer to update the currentViewController property like this:

[[NSNotificationCenter defaultCenter] addObserverForName:@"CurrentViewChanged"
                                                  object:nil 
                                                   queue:nil
                                              usingBlock:^(NSNotification *note)
 {self.currentViewController = (UIViewController *)note.object;} ];

In your view controller implementations, update the viewDidAppear methods to notify the observer that a new view controller is being displayed by adding the following line

[[NSNotificationCenter defaultCenter] postNotificationName:@"CurrentViewChanged" object:self];

Finally, include code in the applicationDidBecomeActive method in your app delegate to force the modal display of your login screen.

UIStoryboard *mainStoryBoard = self.window.rootViewController.storyboard;
UnlockViewController *uvc = [mainStoryBoard instantiateViewControllerWithIdentifier:@"modalUnlockView"];
uvc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self.currentViewController presentViewController:uvc animated:YES completion:NULL];

A couple of additional items to note :-

  1. You can disable the login screen display at anytime by posting a notification where the view controller passed is nil.
  2. You only need to post the notification once for a navigation view controller at the top level. All view controllers in the navigation controller stack will be covered. I haven't checked, but I suspect the same is true for a tab view controller.
  3. If you want to display the login screen the first time you enter the app after startup then include the following line in the applicationDidFinishLaunching method.

    self.currentViewController = self.window.rootViewController;

I hope this is of some use.

Thanks

drew
  • 2,371
  • 2
  • 19
  • 27