Storyboard Segue not loading view - objective-c

I'm trying to segue in code. the prepareForSegue function runs and shows correct destination view controller, but nothing happens. Any idéas on what I'm missing or what I have misconfigured?
View controller possible path:
A ->B (sgueResultat)
or
A->C (sgueStopSplash)
Code that chooses the segue:
if (proversion)
[self performSegueWithIdentifier:#"sgueResultat" sender:self];
}
else {
[self performSegueWithIdentifier:#"sgueStopSplash" sender:self];
}
`
The prepareForSegue that I can confirm is running by NSLog:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Source Controller = %#", [segue sourceViewController]);
NSLog(#"Destination Controller = %#", [segue destinationViewController]);
NSLog(#"Segue Identifier = %#", [segue identifier]);
Nslog output:
2012-06-26 22:22:26.002 ClosetV2[2333:fb03] Source Controller = <ABStartViewController: 0xeb12270>
2012-06-26 22:22:26.002 ClosetV2[2333:fb03] Destination Controller = <SplashAfterStopViewController: 0x6b2c9e0>
2012-06-26 22:22:26.003 ClosetV2[2333:fb03] Segue Identifier = sgueStopSplash
2012-06-26 22:22:26.003 ClosetV2[2333:fb03] sgueStopSplash
Regards
Andreas

Make sure your segues are set to "modal" in your storyboard (or custom if you are fancy).
I remember when I first started using segues when storyboarding came out, I kept trying to use push, which you can only do if you have an embedded UINavigationController. Otherwise, a push segue will simply not function.
Another thought... where is the code below executing? If an animation is already taking place or if the current view is not already showing on the screen, it will not function properly. For example, if you have this code in your viewDidLoad, it will not work.
if (proversion)
[self performSegueWithIdentifier:#"sgueResultat" sender:self];
}
else {
[self performSegueWithIdentifier:#"sgueStopSplash" sender:self];
}
Edit: Updated Answer
Waiting for the [self dismissModalViewController:YES] animation to complete before performing your segue is actually annoying and somewhat messy. I don't think there is a "proper" way to do it. However, if you put the following method inside the view that has the modal controller and send it a message after using [self dismissModalViewController:YES], you should be in good shape.
- (void)waitUntilModalControllerIsDismissed
{
if(self.modalViewController)
{
[self performSelector:#selector(waitUntilModalControllerIsDismissed:)
withObject:nil
afterDelay:0.1f];
return;
}
else
{
//At this point, the modal animation will be completed and you can perform your segue if you want
}
}

Related

Performwithsegue and programatically switching views - Objective-C

I am having a problem, I want to change to another viewcontroller when a timer expires and this works with this code:
- (IBAction)Akkoord:(id)sender {
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"Innameformulier"];
[self presentViewController:vc animated:YES completion:nil];
[self performseguewithidentifier:#"nextcontroller"]
}
But when I use this, my variables in my prepareforsegue method are not passing. How can I do this? I already tried [self performseguewithidentifier] but this is not working.
my preparforsegue code is:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
Innameformulier *IForm = [segue destinationViewController];
IForm.SignatureTransport = _drawImage.image;
IForm.KlantnaamInname = _Klantnaamtransport;
}
How can I call this function to happen on the timer?
In Interface Builder, select the View Controller from which you want to fire a segue, CTRL-drag from it to the destination View Controller and create a segue.
Select the segue, open the Attributes Inspector and create an Identifier for it.
Go back to your View Controller Class that fires the segue and if you don't already have it commented, add the method prepareForSegue:
In your prepareForSegue: method you should have something like the following:
- (void)prepareForSegue:(UIStoryboardSegue *)segue {
if ([segue.identifier isEqualToString:#"XXXX"]) {
DestinationVC *dVC = segue.destinationViewController;
dVC.attribute1 = self.anAttribute;
dVC.attribute2 = self.anotherAttribute;
}
}
And now you can fire the segue by calling [self performSegueWithIdentifier:#"XXXX"].
Note: you can also fire an action segue from an UIControl subclass like UIButton
OK, what you are doing here is bypassing the segue completely. You need to do something like this...
- (IBAction)Akkoord:(id)sender {
[self performseguewithidentifier:#"nextcontroller"]
}
This is all you need to do. The segue will then create the nextController for you and then the code inside prepareForSegue will pass the variables across.
If you want it on a timer then you just need to set up a timer and when it expires you can run...
[self performseguewithidentifier:#"nextcontroller"]
As long as you have a segue with this identifier then it will work anywhere. Ever after a timer.

How do I catch when UIViewController displays after dismissViewControllerAnimated

I've got two UIViewControllers. I'm using modal segue to the second one, when coming back I use dismissViewControllerAnimated. I want to fire a method when I come back to the first one. How can I do that?
I tried to fire a custom notification before dismissViewControllerAnimated and catching it in the first UIViewController, but it doesn't catch anything, because it's still on the second one when it's fired.
There are easy options I can see.
Use the viewDidDisappear: method in the view you're dismissing.
dismissViewControllerAnimated:completion: method accepts a block that actually executes after viewDidDisappear executes in the dismissing view.
To pass a reference from one view controller to the next:
In the second view controller's .h file, add a property:
#property (nonatomic,strong) FirstViewController *firstVC;
In your first view controller, add the following method:
- (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender {
if([#"segue_YOUR_SEGUE_NAME" isEqualToString:[segue identifier]]) {
if([[segue destinationViewController] isKindOfClass:
[SecondViewController class]]) {
SecondViewController *dest = (SecondViewController*)[segue
destinationViewController];
dest.firstVC = self;
}
}
}
Now, in your second view controller, you can do two things, as I already stated:
[self dismissViewControllerAnimated:YES
completion:^{
[self.firstVC someMethod];
}];
OR...
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.firstVC someMethod];
}

Attempt to present * on * whose view is not in the window hierarchy

I'm trying to make a modal view controller in my app delegate (I created a function called showLoginView). But whenever I try to call it I get a warning in XCode:
Warning: Attempt to present <PSLoginViewController: 0x1fda2b40> on <PSViewController: 0x1fda0720> whose view is not in the window hierarchy!
Here's the method code:
- (void)showLoginView
{
PSLoginViewController *loginViewController = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:NULL] instantiateViewControllerWithIdentifier:#"PSLoginViewController"];
[self.window.rootViewController presentViewController:loginViewController animated:NO completion:nil];
}
How can I add the view to the window hierarchy? Or maybe I'm doing something very wrong?
You can't display a modal view controller from the appDelegate. You need to display a modal ViewController from whichever viewController is currently displaying full-screen. In other words, you need to put that code into your root view controller, or whichever one you want to display the modal vc from...
Also, you'll want to use the method "presentModalViewController" to present the modal. You can set properties on the modal vc such as:
vC.modalPresentationStyle = UIModalPresentationFormSheet;
vC.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:vC animated:YES];
You can actually present a modal view Controller from the AppDelegate as long as you detect the current visible viewController and take care of the case where you current controller is a navigationController.
Here is what I do:
UIViewController *activeController = [UIApplication sharedApplication].keyWindow.rootViewController;
if ([activeController isKindOfClass:[UINavigationController class]]) {
activeController = [(UINavigationController*) activeController visibleViewController];
}
[activeController presentModalViewController:loginViewController animated:YES];
UIViewController *activeController = [UIApplication sharedApplication].keyWindow.rootViewController;
if ([activeController isKindOfClass:[UINavigationController class]])
{
activeController = [(UINavigationController*) activeController visibleViewController];
}
else if (activeController.modalViewController)
{
activeController = activeController.modalViewController;
}
[activeController presentModalViewController:vc animated:YES];
I ran into this problem on iOS 7 - the key to making any of the proposed solutions work was to call
[self.window makeKeyAndVisible];
in your AppDelegate.
After that call, presenting a modal view from the window's rootViewController worked.
Another reason for that warning can be that you want to present a view controller from an instance which is not the top most view controller.
So first you have to get the topmost UIViewController and using this instance to call presentViewController:
UIViewController *root = [UIApplication sharedApplication].keyWindow.rootViewController;
while (root.presentedViewController) {
root = root.presentedViewController;
}
You can NSLog(#"%#", self.window.rootViewController), and see what the rootViewController really is.
I came into this problem, when the rootViewController is a normal UIViewController.
Replace it with a UINavigationController, wish it will help.
Faced this issue while trying to present controller from the call of delegate of other controller . i.e : show search filter with delegate , once done back to my controller and receive data via the delegate then present controller , all I had to do is to dispatch the present code cause while in a delegate you're in another thread , that's why you're presenting on your view from main thread another controller from that other thread , so have to go back to main thread , just put the presenting code like this :
dispatch_async(dispatch_get_main_queue(), ^{
[self presentViewController:searchVC animated:true completion:nil];
});
Hope this helps !

Can you return data via dismissModalViewControllerAnimated: or do you need a segue for the return journey?

I've got a ViewController, that has a UIButton which performs the following:
- (IBAction)buttonClicked:(id)sender
{
NSLog(#"Button clicked, lets move to next controller to do stuff");
[self performSegueWithIdentifier:#"toNextController" sender:nil];
}
This just moves onto my next ViewController, nothing amazing so far.
In the second ViewController, I will do some of my application logic, then return.
- (IBAction)backButtonPressed:(id)sender
{
NSLog(#"Back button clicked, lets just drop out of here...");
[self dismissModalViewControllerAnimated:YES];
}
- (IBAction)saveButtonPressed:(id)sender
{
NSLog(#"save button clicked, lets send some data back");
[self performSegueWithIdentifier:#"backToMain" sender:nil];
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"backToMain"])
{
NSLog(#"Preparing segue for backToMain");
// Obtain handles on the current and destination controllers
MainController * startingViewController;
SecondController * destinationController;
startingViewController = (MainController * ) segue.sourceViewController;
destinationController = (SecondController * ) segue.destinationViewController;
// set data on the main controller
startingViewController.myString = #"SomeDummyString";
}
}
What I have tried to do so far, is to create a second segue that links back to the main controller, and before performing the segue, grab a handle on it and set data. I'm not sure if that is the best way of navigating back or not.
Question:
Is it possible, to return data when doing a [self dismissModalViewControllerAnimated:YES];, or do you need to implement a segue for the return journey?
Check this out: 10841897
It describes using a delegate and protocol to send the information back and forth. It can be slightly changed to fit your needs, just create a savedWithData: method that sends a dictionary or whatever data you want back to the first view controller rather than just the generic done which is described in the link.
You can do something like
[destinationController setSomeData:#"Sending Something Back"];
This will set an #property in your destinationController before it loads.

Dismiss ViewController + Table ViewController + Master-Detail app

I have a Master-Detail application. Both master and detail are UITableViewControllers. In detail scene I created a button and call to it action
- (IBAction)completeTaskButtonPressed:(id)sender {
[[self delegate] removeCompletedTask:self.indexFromRow controller:self];
}
In Master VC implementation I have method
- (void) removeCompletedTask:(NSInteger)index controller:(DetailViewController *) controller {
[self.dataController.masterTasksList removeObjectAtIndex:index];
[self.tableView reloadData];
[self dismissViewControllerAnimated:YES completion:NULL];
}
These method must delete selected row and go back to the Master View. The problem is that it removes the row but DONT dismiss detail view. Any help will be usefull.
Sounds like your master-detail setup involves a navigation controller. If you want to dismiss the detail view in the same manner as would tapping the Back button, use [self.navigationController popViewControllerAnimated:YES].
try
[self dismissModalViewControllerAnimated:YES];
or you could try:
[self.navigationController popViewControllerAnimated:YES].
You are popping the view controller which is the opposite of pushViewController: