How to use prepareForSegue and avoid errors when using pushViewController? - ios

My segues were added in the storyboard. I want push to a viewController, say Deep_VC, different from the next one in the storyboard, say Next_VC. I'm using:
Deep_VC *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"DeepVC"];
[self.navigationController pushViewController:controller animated:YES];
It goes there, but I get errors. The nav bar tile is for the Next_VC, not the Deep_VC, and the error messages:
Finishing up a navigation transition in an unexpected state . . .
Unbalanced calls to begin/end appearance transitions . . .
My prepareForSegue looks like:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"toNextVC"]) {
Next_VC *vc = [segue destinationViewController];
vc.receivedData = [NSMutableArray arrayWithObjects:passData, nil];
}
if ([[segue identifier] isEqualToString:#"toDeepVC"]) {
Deep_VC *vc = [segue destinationViewController];
vc.receivedData = [NSMutableArray arrayWithObjects:passData, nil];
}
}
Can anyone help, please?

I'd rather use performSegue instead of pushViewController in your case. But wait, if you`ve wired your VCs in the storyboard you don't need to push. This will be done automagically by the segue.
EDIT
if (login == successful) {
[self performSegueWithIdentifier:#"toNextVC" sender:self];
} else {
[self performSegueWithIdentifier:#"toDeepVC" sender:self];
}
After that prepareForSegue will be called automatically and there you set your data. pushViewController is not needed as the seque pushes the appropriate VC.
Hope that helps!

Related

Failed to push to a View Controller in iOS

I'm a very beginner to iOS development. I made a navigation application in iOS to view some details in another view when table view cell tap. I did the following code,
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
LawyerViewController *dvc = [self.storyboard instantiateViewControllerWithIdentifier:#"LawyerViewController"];
NSLog(#"%#",[self.myObject objectAtIndex:indexPath.row]);
dvc.lawyer = [self.myObject objectAtIndex:indexPath.row];
[self.navigationController pushViewController:dvc animated:YES];
}
This is going to the next view. But dvc.lawyer is not null here. It's null on Next View page.
Reading the Value in Next page
NSLog(#"%#",self.lawyer.firstName);
How can I fix this.
Thanks in Advance!
You are supposed to instantiate ViewControllers in another way, if you use storyboard segues. You need to implement prepareForSegue where you can Access the segues destinationViewController like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// reference to the destination view controller
LawyerViewController *vc = [segue destinationViewController];
// Pass any data
vc.lawyer = self.myObject[[self.tableView indexPathForSelectedRow].row]; // Not tested
}
}

How can i add 2 segue on 1 action?

I have a tableview which is showing my array items. . I connected push style segue to detailviewcontroller screen with my storyboard but i dont want to all items go detailviewcontroller so i made a controller like that ;
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if (sender == self.btnEkle) return;
if (sender == self.btnKrediKartlarim) return;
NSString *bankaAdi = [[mainList objectAtIndex:indexPath.row] objectForKey:#"BankaAdi"];
if (bankaAdi.length > 1) {
KartDetay *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"KartDetay"];
[self presentViewController:vc animated:YES completion:nil];
}
If bankaAdi.length > 1 my app should go to the KartDetay
if its not i mean else my app should go to the detailviewcontroller
these codes are working but there is an error in my compiler.
Unbalanced calls to begin/end appearance transitions for .
Sorry for my English i know i didn't describe myself clearly but please try to help me.
Thanks !
---UPDATED AREA----
First of all Thank you for answer.But it doesnt work or i couldnt do that.
1- I created 2 manuel different segues to my KartDetay("taksit" segue name) and my DetayEkran("detay" segue name)..
2-I used with these codes..
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *indexPath2 = [self.tableView indexPathForSelectedRow];
bankaAdi = [[mainList objectAtIndex:indexPath2.row] objectForKey:#"BankaAdi"];
if (bankaAdi.length > 1)
{
[self performSegueWithIdentifier:#"taksit" sender:nil];
}
else
{
[self performSegueWithIdentifier:#"detay" sender:nil];
}
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"taksit"])
{
//if (sender == self.btnEkle) return;
//if (sender == self.btnKrediKartlarim) return;
KartDetay *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"KartDetay"];
[self presentViewController:vc animated:YES completion:nil];
}
else
{
DetayEkran *detayEkran = [self.storyboard instantiateViewControllerWithIdentifier:#"DetayEkran"];
[self presentViewController:detayEkran animated:YES completion:nil];
}
When I run my app and tap my first cell which is bankaAdi>1.
App can go to KartDetay screen but my compiler says :
Unbalanced calls to begin/end appearance transitions for .
Thank you for answer again.
----ReUpdated Area --- problem is solved by Greg... Thank you for that Greg...
I made a huge mistake with these codes coz i call another DetayEkran *detayEkran = [self.storyboard instantiateViewControllerWithIdentifier:#"DetayEkran"];
[self presentViewController:detayEkran animated:YES completion:nil];
in my prepareforsegue method. When i delete all instantiate codes in my prepareforsegue methods my app working fine...
So
Greg codes are working like a charm.. Thank you Greg !
When the segue is called the prepareForSegue:segue method is called and it handles the transition, you shouldn't call presentViewController or push view controller manually.
The best way to do that is create two segue for KartDetay and detailviewcontroller with two different identifiers in storyboard.
And override didSelectRowAtIndexPath method, where you check your condition and run appropriate segue:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *bankaAdi = [[mainList objectAtIndex:indexPath.row] objectForKey:#"BankaAdi"];
if (bankaAdi.length > 1) {
[self performSegueWithIdentifier:#"YOUR1IDENTIFIER" sender:nil]
}
else
[self performSegueWithIdentifier:#"YOUR2IDENTIFIER" sender:nil]
}
If you need to pass any parameters use prepareForSegue method:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"YOUR1IDENTIFIER"]) {
KartDetay *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"KartDetay"];
[self presentViewController:vc animated:YES completion:nil];
}
else {
//handle other view controller
}
}
Just remember to replace segue identifiers with your one.
The prepareForSegue:sender: method is invoked before opening the detail view controller. It is the place to prepare for the transition, not to present/push view controllers. The actual transition is done after the method has been invoked. Whether push or present is used, depends on the segue type in the storyboard.
Try using the tableView:didSelectRowAtIndexPath: method instead of the prepareForSegue:sender: method. This should solve your problem.

Is there any way to push a vc in a storyboard in init with coder?

So I have a problem when trying to push some Viewcontrollers basically when the app loads it checks if you are already registered and if you are it sends you to a diff vc and if your not registered it sends you to a RegisterVC. It's done in storyboard and the problem is that when I put the code in viewDidLoad the pushes works but I can't see the rootviewcontroller from the storyboard but if I move the code into the init with coder I can see the viewcontroller but the push return's nil in the method that's supposed to push to a new vc, so the transition never happens.
The code looks like follows:
if (emp == nil) {
[self gotoRegisterView];
}
else {
[self gotoSMWView];
}
and :
- (void) gotoRegisterView {
UIViewController* vc = [self.storyboard instantiateViewControllerWithIdentifier:#"RegisterVC"];
[self.navigationController pushViewController:vc animated:YES];
}
- (void) gotoSMWView {
UIViewController* vc = [self.storyboard instantiateViewControllerWithIdentifier:#"SMWVC"];
[self.navigationController pushViewController:vc animated:YES];
}
Any suggestions are much appreciated.
If you're using storyboards, just connect the main scene to any other scene you want to call from there. Then, Ctrl+Drag from the initial VIEW CONTROLLER (not elements on the view controller, but from the controller itself). Then click on the segues you just created and give them good descriptive names. For this example, we'll just say segue1 and segue2.
Now, if segue1 takes you to the RegisterView, and segue2 to SMWView then you can do this:
- (void) gotoRegisterView {
[self performSegueWithIdentifier:#"segue1" sender:self];
}
- (void) gotoSMWView {
[self performSegueWithIdentifier:#"segue2" sender:self];
}
If you need to do any other initialization or set up on these view controllers, you can override this method:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
Within this method, you can check which segue has been called using this template:
if([[segue identifier] isEqualToString:#"segue1"])
And you can get an instance of your destination view controller like this:
YourViewController *vc = [segue destinationViewController];

Set Method Values With prepareForSegue

Basically, i'm using the prepareForSegue method to transition to another view within my storyboard, my view had to be embedded in a navigation controller in order to display the navigation bar so I am passing variables in such a way:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"exploreAddSelected"]){
UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
AddTableViewController *controller = (AddTableViewController *)navController.topViewController;
controller.tagName = tagName;
}
}
My issue is I need to be able to set some method values in the actual view controller when using the prepareForSegue method, as you can do when using pushViewController as below:
DetailViewController *detailViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailViewController"];
detailViewController.tagName = tagName;
[detailViewController setCurrentHashtag:nil];
[navigationController pushViewController:self.detailViewController animated:YES];
I need to be able to set the "setCurrentHashtag" method, that is declared in the view controller that the segue "exploreAddSelected" goes to. How would I do this?
The answer to this is actually extremely obvious, but it takes me to ask the question to realise the answer myself.
You can simply set:
controller.currentHashtag = nil;
Where currentHashtag is a newly declared instance in the view controller.
Then in the actual view controller set:
[self setCurrentHashtag:currentHashtag];
Just add the currentHashtag to the method.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"exploreAddSelected"]){
UINavigationController *navController = (UINavigationController *)segue.destinationViewController;
AddTableViewController *controller = (AddTableViewController *)navController.topViewController;
controller.tagName = tagName;
[controller setCurrentHashTag:nil]; //add this line
}
}
I'm not sure what you are doing here. If the segue points to a view controller directly (and nor via another navigation controller), you do not need the mapping to topviewcontroller, but use the destinationcontroller directly.

Deactivate push-animation in segue

I've one problem. I have a ViewController1 whcich opens the ViewController2 through a push-segue. //Both are NavigationControllers
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"show2"])
{
ViewController2 *vc2 = [segue destinationViewController];
}
}
But is it possible to deactivate the animation of this push-action, so it directly shows the new ViewController?
Why not just do something like this?
[ViewController1 pushViewController:ViewController2 animated:NO];

Resources