I am trying to switch views on button press event, but when i press the button to switch the view from firstview to second. It shows the secondView for a sec or so and then a blank page appears. Im new to iOS programming so not getting what might be the issue.
Here is my code :
- (IBAction)okPressed:(id)sender {
AppDelegate *mainDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
shipView = [mainDelegate.storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self.navigationController pushViewController:shipView animated:YES];
The UIStoryBoard is instantiated in AppDelegate class. When the okPressed Method is invoked the SecondViewController is not loaded.
The standard alloc / init will not do anything. You need to either use initWithNibName:bundle: using the filename of your XIB, or UIStoryboard's instantiateViewControllerWithIdentifier: using the identifier of the controller that you defined in the storyboard file.
Related
I have a viewController A which will both added into viewController hierarchy by being pushed by view B(presented) and being pushed by view C(pushed).
ROOT->...-(-present-)->B-(-push-)->A
ROOT->...-(-push-)->C-(-push-)->A
And now I have a button in viewController A which needs to change the window.rootViewController, but I cannot make it functions correct in both conditions.
When I use [self.navigationController popToRootViewControllerAnimated:<#(BOOL)#>];, it will not dismiss the presented view B.
Also [[[UIApplication sharedApplication] keyWindow].rootViewController dismissViewControllerAnimated:YES completion:<#^(void)completion#>]; is not the solution, because when there is no presented view completion block will not be called.
If I combine those two methods, I think it will work only when I pass a parameter to every viewController in the hierarchy.
So is there a rough way to clear the viewController hierarchy?
Or is there any other solution?
You can set rootViewController from anywhere in application like,
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
appDelegate.window.rootViewController = #"desired root VC"; // instatntiate your VC and set as root VC of your window
And don't forget to implement AppDelegate.h in that class.
I am trying to set the delegate of a view controller from my app delegate.
But it does not work.
AppDelegate.m:
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle:nil];
SFLoginViewController * LoginVC = (SFLoginViewController *)[sb
instantiateViewControllerWithIdentifier:#"Login"];
LoginVC.delegate = self;
SFLoginViewController.m
- (IBAction)Login:(id)sender {
NSLog(#"%#",self.delegate); //returns nil (!!)
//It should call the delegate method here
[[self delegate] LoginSucceeded];
}
any help?
Why not set your delegate in the ViewController like this:
self.delegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
Then you'll be able to handle delegate events in your AppDelegate.
Looking at the instantiateViewControllerWithIdentifier documentation...
Discussion You use this method to create view controller objects that
you want to manipulate and present programmatically in your
application. Before you can use this method to retrieve a view
controller, you must explicitly tag it with an appropriate identifier
string in Interface Builder.
This method creates a new instance of the specified view controller
each time you call it.
I don't think the code you have in your appDelegate is returning the ViewController that is presented via the storyboard
By doing this
(SFLoginViewController *)[sb instantiateViewControllerWithIdentifier:#"Login"];
you are creating a new instance of SFLoginViewController.
I assume that you already have an instance of this viewcontroller created from the storyboard.
The instance from the storyboad is the one who call its method login:(id)sender and not the one you assigned the delegate.
Try #hw731 answer or you need to add the delegate to the instance created from the storyboard (not to the one you'are creating in your appdelegate).
If I show a viewcontroller in iOS using instantiateViewControllerWithIdentifier, I can not leave the viewcontroller without crashing. The view loads fine and performs its tasks but when i try to leave it by pushing a button the app crashes. Is this because of some state that is wrong or have i made another mistake?
Code:
- (IBAction)push:(id)sender {
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:[[NSBundle mainBundle].infoDictionary objectForKey:#"UIMainStoryboardFile"] bundle:[NSBundle mainBundle]];
NSLog(#"story: %#",mainStoryboard.description);
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
ListViewController *controller = (ListViewController*)[mainStoryboard instantiateViewControllerWithIdentifier: #"ListId"];
appDelegate.window.rootViewController = controller;
}
You're changing the applications root view controller as a result of pressing a button on the previous root view controller. That's not really how navigation in an iOS app should be done. Instead, try embedding your root view controller in a UINavigationController and then push and pop view controllers through it to navigate around your app.
If your interface doesn't fit a navigation paradigm, you could use presentViewController:animated:completion:.
Regardless, you should read the View Controller Programming Guide as it addresses the best practices of displaying views.
I want to know if it is possible to have a first view that acts as a menu (that has a couple of buttons for which one is Edit). I want to be able when I click on edit to then show a split view. Now, when I do that, I get the error :
Application tried to present a Split View Controllers modally
My code in the action method of the edit button is :
UIStoryboard *editorStoryboard = [UIStoryboard storyboardWithName:#"EditorStoryboard" bundle:nil];
UIViewController *editorViewController = [editorStoryboard instantiateInitialViewController];
editorViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:editorViewController animated:YES completion:nil];
So I am assuming, the ViewController that contains the button is the root VC. You should change that with the SplitVC when tapping the button (add a nice animation), because the split should be the root of your app (it should not be presented modally). Hope this helps!
Edit:
It should look something like:
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
appDelegate.window.rootViewContrller = mySplitViewController;
You can also do this in your custom segue if you have one.
I am working on an app that at launch checks for valid login credentials, and if they are found and not expired the main split view controller is displayed, and if not a login screen should be displayed.
Each part is working fine separately, but I am struggling with the best way at launch time to select the proper view to display.
I have tried setting up a modal segue from the root view controller, and in my application:didFinishLaunchingWithOptions: function in the App Delegate, calling this:
// Segue to the login view controller...
if (loginNeeded) {
[self.window.rootViewController performSegueWithIdentifier:#"LoginScreen" sender:self];
}
This logically should work, but triggering segues from within the app delegate seems to be impossible.
What is the ideal place and technique for handling this?
You could try a custom segue, as per this post hiding-a-segue-on-login-process.
Alternatively if you're desperate to have the login display before the split view controller loads try something along the following lines...
Create your login screen on the main storyboard as, say, a subclass of UIViewController. Make sure it is the initial scene (check Is Initial View Controller).
On the storyboard, create a new segue from your login class to the original SplitViewController. Give it an identifier, 'Load SplitViewController' and a segue custom class name which we'll call FullyReplaceSegue.
In your login class .m file, add code to be called once the user has logged in:
[self performSegueWithIdentifier:#"Load SplitViewController" sender:self];
Create the new segue class, based on UIStoryboardSegue and name it FullyReplaceSegue as per above.
.h file
#import <UIKit/UIKit.h>
#interface : UIStoryboardSegue
#end
.m file
#import "FullyReplaceSegue.h"
#implementation FullyReplaceSegue
- (void)perform
{
UIViewController *dest = (UIViewController *) super.destinationViewController;
UIWindow *window = [UIApplication sharedApplication].keyWindow;
window.rootViewController = dest;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
UISplitViewController *splitViewController = (UISplitViewController *)dest; // assumes we're transitioning to a UISplitViewController!
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
splitViewController.delegate = (id)navigationController.topViewController;
}
}
#end
Here's how I did it.
In didFinishLaunchingWithOptions:
//save the root view controller
[[self window] makeKeyAndVisible];
UINavigationController *navigationController = (UINavigationController*) self.window.rootViewController;
rootController = [[navigationController viewControllers] objectAtIndex:0];
Somewhere else in the app delegate:
[rootController performSegueWithIdentifier:#"fileSegueID" sender:self];
Then, in the storyboard, create a segue from the view that gets assigned as "rootController", to the desired optional view, and give that new segue the id fileSegueID. It takes some debugging to make sure the rootController variable gets assigned to the correct view.
Maybe a little late, but I was looking for the same suggestions. Here's what I wound up doing.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Signup" bundle:nil];
if(isLoggedIn) {
UINavigationController *navigationController = (UINavigationController*) self.window.rootViewController;
IndexController *ivc = [storyboard instantiateViewControllerWithIdentifier:#"IndexController"];
[navigationController pushViewController:ivc animated:NO];
}
Why don't you load the screen that would be visible assuming proper and non-expired log-in credentials (by setting it as the root view controller of the window), and then in viewDidLoad of that first view controller, check if an update to the login credentials are needed. If so, segue into the login view controller.
Yes, it can be used, if you get a reference to the segue's parent view controller. You can get it like this:
UINavigationController *navigationController = (UINavigationController*) self.window.rootViewController;
[[[navigationController viewControllers] objectAtIndex:0] performSegueWithIdentifier:#"LoginScreen" sender:self];
This will only work if the index in viewControllers array matches the one of your view controller and if it exists of course. In this case is the first one (in the array and storyboard).
The segue ("LoginScreen") must not be attached to an action. The way you do this is by control-dragging from the file owner icon at the bottom of the storyboard scene to the destination scene. A popup will appear that will ask for an option in “Manual Segue”; pick “Push” as the type. Tap on the little square and make sure you’re in the Attributes Inspector. Give it an identifier which you will use to refer to it in code.