Storyboard controller initialisation, where can I place pre-init code? - ios

so I have a simple application using a storyboard. I have a few view controllers linked by segues. I also have one controller set as the default "first view controller". I understand that no code is required for the app to automatically load this was the first controller. However I want the app to first run a few checks (i.e. is the user logged in) before it decides which controller to push. Is there anywhere I should be putting this code or should I remove the "first view controller" setting on the storyboard and init manually?
Thanks

you can set the LoginViewcontroller as initial viewcontroller and if the user is logged in change the initial viewcontroller to something else, you can change the initial view controller by changing the rootViewController property of the window

I would leave your first controller as is, and check in AppDelegate if you want to show Login screens. If you do show them push that controller, otherwise, show your "first view controller".

Related

iOS - Will the ViewController be deallocated after it's been removed from the parent controller?

I'm working on a app with register/login.
My root controller is a UITabBarController.
Every tab is a view controller individually.
I want to make one of them a login tab.
Every time the app is launched and the user switches to this tab, it checks whether the user is logged in. If not, it presents a register controller while it presents a login controller when the user is logged in.
To implement the function, I wrote two view controllers separately (the register one and the log in one).
To obey the MVC style, I also make two UIView class to render the view.
To summarize, the structure is
root viewcontroller(UITabBarController) -> user tab controller(UIViewController) -> login/register view controller(UIViewController -> login/register view(UIView)
login/register controller is a childViewController of user tab controller.
After the user has registered, I want the register controller to be removed from the user tab controller, which is its parent controller.
As I handle the touch event in the view(UIView), I make a protocol in it and make the user tab controller to be its delegate.
When the registration is completed, the view tell the delegate to remove its child controller.
#pragma mark - RegViewDelegate
-(void)parentViewControllerPop{
[_cRegController removeFromParentViewController];
NSLog(#"_cRegController removed from parent viewcontroller");
}
However, after that, the view is still showing on the screen, why?
I don't think what the design is a good one, but I don't know what is the best way to implement what I want.
Can anyone help?
To remove a child view controller from his parent you need to do this 3 steps:
viewController.willMoveToParentViewController(nil)
viewController.view.removeFromSuperview()
viewController.removeFromParentViewController()
Reference: Removing a Child View Controller.

Can I send performSegueWithIdentifier: to anything other than self?

I have a category on UIViewController that deals with errors coming from my networking layer. If I get an authentication error in response to a network call, I want to perform an unwind segue which takes me back to my LoginViewController.
However, I don't want to have to add the appropriate unwind segue to every single view controller in my Storyboard. Can I simply declare the unwind segue in the UITabBarController that is at the "top" of my view controller navigation, and then say
[self.tabBarController performSegueWithIdentifier:#"UnwindToLoginSegueIdentifier" sender:self]
... from inside my UIViewController+ErrorHandling category?
No, you can't do that. The unwind segue has to come from the controller you're unwinding from, and all segues need to be connected from a particular instance in the storyboard. The login view controller really should be one that's presented modally, not be one of the tabs, since you only need it briefly, then it should go away. If you set up your app that way, you can present and dismiss it from any controller (present it without animation from the controller in the first tab, if that's what you want the user to see when the app launches). You'll still have to have code in every controller to do that, unless you make a common base controller with that functionality that all the other controllers inherit from.

How to implement an iOS login screen that only appears for unauthenticated users

I know this question is a bit open-ended but I'm trying to make it as specific as possible because I don't really know what a standard convention would be for this type of thing with iOS. I have been looking into implementing a login screen on my app, however I am having trouble figuring out the best way. I have three methods listed below, could anybody tell me if one of these is better or a more correct approach? (or if there is something that I totally missed).
The first approach - I initially have a navigation controller as my root controller with the login screen being the first view on the stack. Then when the user logs in, i just push the main UI to the stack. The user can then use the back button to return to the login screen. I know this technique works but then when re-launching the app, the user doesn't need to login again. I'm not sure should I just set up the stack the same way (login page first) and then push the main UI on top? Is that a common technique?
The next approach, I found here how to replace the root controller How to change RootViewController (in AppDelegate) from within CustomViewController? I like this idea better where I could just get rid of the login screen after login and add some type of button to bring it back on logout. Then during re-launch I can just skip adding the login screen altogether.
The third approach is perhaps overlaying the login on top of the main UI but I haven't found any code to do this. It also seems a little weird because my main UI might start firing messages that i wouldn't want to occur until after login so I'd have to account for that.
I would suggest you to have a root view controller with a blank view. This controller is set as a root view controller in the AppDelegate's applicationDidFinishLaunching: method.
Role of this root view controller would be to show the login screen through login view controller initially. Login view controller delegates to root view controller upon successful login to remove itself from root view and root view controller then set the next controller to be displayed.
This way you can manages multiple views if any before showing the main view through your root view controller.
There are different ways to display login view on top of root view.
1) Present a login view controller without animation.
2) Add login view as a subview on top of root view [Note: Before iOS 5, you don't get the rotation and view life cycle call backs and you should write your own code to pass the callbacks to the view added on top of root view. From iOS 5 onwards you have view containment concept using which you can maintain parent child relationship.]
Hope this helps.
We have a similar app. Our storyboard looks a little like a wheel.
We have a navigation controller as our root controller, which then goes to a view controller with a spinner on it. That controller handles the call to see if the user is logged in or not. It is connected to two different controllers.
If they are already logged in, it goes to the main view controller. If they haven't logged in, it goes to the login view controller. The login view controller will go back to initial view controller on success, and since they'll then be logged in, it goes to the main controller.
To fall back, we go all the way back to the initial view controller with the spinner on it.
You can hide the navigation bar on every view before the main one.
I always implement it with storyboard. Just add Storyboard ID to your login view controller, say Onboarding.
Then write something like this in application: didFinishLaunchingWithOptions:
if (![[NSUserDefaults standardUserDefaults] objectForKey:TRAIN_COMPLETE]) {
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.window.rootViewController = [storyboard instantiateViewControllerWithIdentifier:#"Onboarding"];
}
All our ViewController are subclassed from a custom subclass of uiviewcontroller. This allow us to make powerful enhancements on behavior, constraints, ...
Our super view controller class handle authentification by summoning a modal view on viewWillAppear if user is not logged in.
Works like a charm to handle disconnection and resuming from any point in the app.

Storyboard with conditional ViewControllers

I'm new working with Storyboards, so I'd appreciate any help!
I have a Settings view controller which should only appear if no previous settings exist. If those have been set, a different vc (the main one) is loaded.
I tried using the method in the attached image, but I'm not sure that's correct...
In the RootViewController I'm testing in viewDidLoad if settings were previously set or not, and am triggering the Segue with either ShowMain or ShowSettings as identifiers.
[self performSegueWithIdentifier:#"ShowMain" sender:self];
Of course RootViewController shows up in the NavigationController hierarchy (with the back button showing), which I don't want.
How should I be going about this?
Tia!
S.
If, as it seems, the RootViewController only exists to decide which real controller to show, I'd suggest you get rid of it. Your main controller can be set as the first controller and have the settings logic in its viewDidLoad. Then, make your settings controller be presented using a modal segue. Once you're finished with the settings (if necessary), dismiss it and you're back to the main one.

Pop the current view using Segues/Storyboard on iOS 5

I am creating an app using iOS 5 SDK. I managed to push views using the Storyboard's Segues, but I cannot find the proper way to pop the current view and go back to the previous one.
I am not using any navigationController (the app doesn't have any top or bottom bars).
I don't think using modal or push segue the other way would be the solution as it instantiates a new controller.
Do I have to use a custom Segue with the opposite animation and deletion of the view at the end ? Or is there a better way ?
Storyboards in iOS 5 don't provide a "no-code" way to return from a segue -- that's something you'll need to implement yourself.
If you use "push" segues (which require a navigation controller), use the navigation controller's popViewControllerAnimated: method to undo the last push segue. (Or other methods to undo more; see the UINavigationController documentation.)
If you use "modal" segues, call dismissViewControllerAnimated:completion: on the view controller which presented the current view controller (which you can get from its presentingViewController property).
Update: In iOS 6 and later there's unwind segues for going "back" in a storyboard. It's still not a no-code solution -- and it shouldn't be, because you need to be able to do things like differentiating between "Done" and "Cancel" exits from a modal view controller. But it does let you put more of the semantic flow of your app into the storyboard. Apple has a tech note that describes them in detail, and they're also covered in the video from WWDC 2012 Session 407.
You could try calling [self dismissViewControllerAnimated:YES completion:nil]; from the controller you want to dismiss (whether the controller has been pushed, or shown modally).
Here is the related documentation : UIViewController Class Reference
The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, it automatically forwards the message to the presenting view controller.
Just to clarify.
In the class that was pushed. Simply wire up the following and the controller and view will be popped off.
[self.navigationController popViewControllerAnimated:YES];
Create Segue type "Custom" on your stroyboard. This can be from a button.
Create a new UIStoryboardSegue class named "popSegue"
In the popSegue.m file add the following;
-(void)perform{
UIViewController *sourceViewContreoller = [self sourceViewController];
[sourceViewContreoller.navigationController popViewControllerAnimated:YES];
}
-In the storyboard editor.
-Select the segue and change the Segue Class to "popSegue"
-Set the Identifier to "popSegue"
Done!
You can use the same "popSegue" class throughout your project.
Hope this helps
I'm using Xcode 5 also and here's how it's done. First, in the view code file that pushed the other, create an IBAction method in the .h file such as this:
- (IBAction)exitToHere:(UIStoryboardPopoverSegue *)segue sender:(id)sender;
Then in the .m file add this:
- (IBAction)exitToHere:(UIStoryboardPopoverSegue *)segue sender:(id)sender {
}
You can add any cleanup code you want executed in this method. Next go to your storyboard and select the pushed view. I assume you've got some kind of button on the view that the user taps to signal he's finished. Click on that button, hold down the key and drag to the the green box below the view which is the Exit. Release the mouse button but continue to hold the key. A popup will appear and your method will show in the list. Select that method. Now when the user clicks on the button, the view will pop and you'll be returned to the starting method.

Resources