0

What is the best approach to create an iOS app login screen that slides in (by presenting it modally) whenever the user isn't logged in?

A user will be "logged out" in the following circumstances:

  • he has never logged into the app (i.e. first use)
  • he has explicitly logged out of the app
  • he is logged out on the server (e.g. his security token has expired on the server, and that is communicated to the app)

My app consists of a UINavigationController that is set as the app's RootViewController, and each screen (other than the Login screen), is pushed onto the NavigationController as the user navigates the app. One of the screens a user can navigate to (i.e. that is pushed onto the stack) is the Logout screen (where the user can log out of the app). The Login screen should appear modally when needed, and the logic and presentation should happen from one centralized place. I am using Storyboards.

What I have tried is to subclass UINavigationController (for the RootViewController), and in its viewDidAppear method I check whether the user is logged in (I store a flag in NSUserDefaults). If he is logged in, the app's first screen is (programmatically) pushed onto the stack; if he isn't logged in, the Login screen is (programmatically) presented modally.

This approach has the following two issues:

  • you cannot set a background image for the subclassed UINavigationController, so a blank screen appears for a short while
  • the subclassed UINavigationController's viewDidAppear is not called when popping to its RootViewController (specifically when popped from the Logout screen)

Ideally I want one central place to check whether a user is logged in (I was hoping the subclassed UINavigationController's viewDidAppear method would be this spot) to check the user's logged-in state, and present the modal Login screen if needed.

I have looked at Login Screen using Storyboard and Example for login screen modally based on storyboard (and others referenced in these) but none of them address the issue of presenting the modal Login screen from a central point.

Community
  • 1
  • 1
mrtnkrstn
  • 318
  • 5
  • 15

4 Answers4

0

First you should note, that as per Apples developer notes, you are not supposed to subclass UINavigationController.

Second, this is fairly opinion based, however I suggest you should use your application delegate class as the pillar point for checking login status, it's a singleton as UINavigationController, effectively is.

Woodstock
  • 22,184
  • 15
  • 80
  • 118
  • How would I go about _when_ to check login status in AppDelegate? I.e. is there a method that gets called "regularly" enough (like `viewDidAppear` in a ViewController) where I can put the check? – mrtnkrstn Feb 27 '14 at 05:52
0

I would suggest posting an NSNotification that your AppDelegate can listen for so that the AppDelegate takes responsibility for presenting your modal login view.

Your communication layer can be responsible for posting the notification whenever the user logs out or the server responds saying that the token has expired.

Mike Pollard
  • 10,195
  • 2
  • 37
  • 46
0

Try presenting the UINavigationController modally from a "Login ViewController":

On app launch, the LoginVC is shown, requiring the credentials. If the login succeeds, push the UINavigationController.

When the login is invalidated (logout, cookie expires, 401 from server, ...), dismiss the UINavigationController and return to the LoginVC.

Note that on returning to the LoginVC all application state is lost, which may or may not be what you want.

Your AppDelegate should retain a reference to the LoginVC, through which you can call the 'dismiss', e.g.

[((YourAppDelegate*)[[UIApplication sharedApplication] delegate]) fallbackToLoginVC]
Hendrik Demmer
  • 191
  • 1
  • 6
  • This means that the LoginViewController will always be on the View Controller stack; is that not a bad thing (esp from a memory usage perspective)? – mrtnkrstn Feb 27 '14 at 05:58
0

OK so here is what I ended up doing:

As pointed out by John Woods, don't subclass UINavigationController. Instead, I created a base UIViewController, which in its viewWillAppear checks whether the user is logged in; if not, modally present the Login screen. All View Controllers that need to check the logged-in state inherit from this base View Controller, so it becomes the "central point" for checking the logged-in state (I don't like using the AppDelegate for this kind of logic).

I like Mike Pollard's suggestion of using notifications to notify when the user's token expires (since this may happen well before viewWillAppear is called). Subscribing to this notification can then also be done in the base View Controller.

Hendrik Demmer's solution is probably the most straightforward, but I don't like having a Login screen "lurking" around at the bottom of the view controller stack - or is this just nitpicking?

mrtnkrstn
  • 318
  • 5
  • 15