How to use Modal View Controllers correctly? - ios

I have a tabbed Iphone project in which I am attempting to present one modal segue but from multiple different view controllers.
Essentially I want it to function the same way the stock music app works in IOS 9 for iphone. You can be in any one different tab and still be able to view the account page.
Demonstration
First problem/question.
How to mimic this behavior without making a ton of segues. Currently I have 3 separate views that I want to call a modal segue from but how can I achieve this without making duplicate segues
Second problem/question.
How to dismiss the modal view without it becoming a deprecated segue. I have found tuts on how to do this but they require another segue back to the "sender" view controller.
If only apple could provide some decent sample code to aid my efforts in my attempt to do this...

you can present and dissmiss any view controller object without segue like below,
UIViewController *vc = [[UIViewController alloc]init]; // your view controller here
// You can present VC like
[self presentViewController:vc animated:YES completion:^{
// do your task on completion
}];
// In your Presented VC you can dissmiss it like
[self dismissViewControllerAnimated:YES completion:^{
//do your task on completion
}];
Update as per comment :
You can instantiate story board like,
SideMenuViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"sideMenu"];
Here SideMenuViewController is custom viewController class set to viewcontroller from storyboard.
And make sure you have set storyboard Id under identity from identity inspector. Here my sideMenu is storyboard Identity!
So you can instantiate your storyboard viewcontroller like this and then present it as mentioned before
Hope this will help :)

Related

Change ViewController

I have a multi-player game where I want it to start after I press a button in the menu. The problem is I don't know how to transit from the menu to the game directly after I start multiplayer.
In ViewController.m
- (IBAction)multiplayer:(id)sender {
[Nextpeer launchDashboard];
}
In AppDelegate.m
-(void)nextpeerDidTournamentStartWithDetails:(NPTournamentStartDataContainer *)tournamentContainer {
UIStoryboard *storyboard = self.storyboard;
ArcadeView *svc = [storyboard instantiateViewControllerWithIdentifier:#"arcade"];
[self presentViewController:svc animated:YES completion:nil];
srandom(tournamentContainer.tournamentRandomSeed);
[tournamentContainer tournamentIsGameControlled];
}
I'm getting the error of
"Property'storyboard'not found on object of type 'AppDelegate *' and
"No visible #interface for 'AppDelegate' declares the selector
'presentViewController:animated:completion:'"
How do I change from one ViewController to another ViewController using storyboard?
Normally in cocos2d, I would do like this:
CCScene *gameplayScene = [CCBReader loadAsScene:#"GamePlay"];
[[CCDirector sharedDirector] replaceScene:gameplayScene];
What's the equivalent?
How do i change from one ViewController to another ViewController using storyboard?
Typically, you'd use a segue to switch from one view controller to another. You can create a segue in your storyboard, connect it to a button, and the button will automatically trigger the segue and transition to the next view controller. As part of the segue process, the existing view controller will get a chance to "prepare" for the segue, at which point it can clean up after itself as necessary and also provide any information that the next view controller might need. Read all about it in the docs for -[UIViewController prepareForSegue:sender:].
There are a number of different ways that you can transition from one view controller to another, of course. You can push a new view controller onto a navigation stack, have a tab bar controller switch between several view controllers, present a view controller, simply remove one view controller's view hierarchy from the window and install the new one, and so on. Many of the possible transitions are provided by existing segue types, but you can also create your own custom transitions by creating your own segues.
If all this is new to you, you should probably spend some time reading through View Controller Programming Guide for iOS.

Creating a central log out view controller in storyboard

I am working with Parse, and one thing I have implemented in my app is their built in PFLogInViewController. This controller will be presented at two times in the application - when the app first starts and the user is not logged in, and when the user taps the "Log out" button of my application (logging out takes them back to the PFLogInViewController, as you are required to sign in to use the app). I would like to set this up using Storyboard, as that is how the rest of my app is laid out. How could I set up a central view controller (a PFLogInViewController) that is accessed at these two times? I have already Subclassed PFLogInViewController and set it up, I just need advice on how to place it in Storyboard and how to connect it to my views. To make this question help as many people as possible, the general theme of my question is how does one establish a central Login/ViewController that can be accessed at different points in the application using Storyboard. Attached is the basic idea of what I'm trying to accomplish. I haven't been able to successfully segue to the initial TabBarController, and I'm not sure how I should make the LoginController the initial ViewController if I can't segue. I am programming in Swift, if it matters.
There are a few ways to do this depending upon your application. One way is drop a UIViewController onto the storyboard, but don't wire it up to anything (no segue). Create a storyboard id for it such as "MyLoginVC". Do the necessary subclassing of UIViewController and attach the class to your VC. Then, when you want to display the VC simply do the following or wire this up to your logout button
id destinationVC = [self.storyboard instantiateViewControllerWithIdentifier:#"MyLoginVC"];
[self.navigationController pushViewController:destinationVC animated:YES];
In addition, if you want to show the login VC as the very first VC when you launch your app, then perhaps in your AppDelegate
// Load Root view controller
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.rootVC = [storyboard instantiateInitialViewController];
self.window.rootViewController = _rootVC;
[self.window makeKeyAndVisible];
// Load Login view controller
id initialVC = [storyboard instantiateViewControllerWithIdentifier:#"MyLoginVC"];
[initialVC setModalPresentationStyle:UIModalPresentationFullScreen];
[_rootVC presentModalViewController:initialVC animated:NO];
When you finish with your login VC (i.e. successful login) then within login VC
[self dismissViewControllerAnimated:NO completion:nil];
and alternatively instantiate your first VC with something similar to the following from within login VC. Note, since you loaded the root VC above first, it is already there with the login VC sitting over it. When you dismiss login VC, the underlying root VC should be ready to rock and roll. Otherwise you can do the following:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
RootTabBarController *tbController = (RootTabBarController *)[self.storyboard instantiateViewControllerWithIdentifier:#"rootTabBarController"];
[self presentViewController:tbController animated:YES completion:NULL];
}
I think what you want is an unwind segue. Here are the instructions I follow for an unwind segue: https://github.com/bradley/iOSUnwindSegueProgramatically
If the link dies, here is what it said:
In your storyboard create two view controllers.
Subclass UIViewController twice, once for each of the view controllers in your storyboard.
Connect these view controllers to the view controllers in your storyboard.
Make a segue between the first view controller and the second by control+dragging from the first to the second.
Click on the segue you created and give it an identifier in the attributes inspector.
Make a button on the first view controller and link it to an IBAction in its UIViewController subclass.
When this button is pressed, the second storyboard should appear. To make this happen (we are doing it programatically) put the following into the implementation of the action you just created:
[self performSegueWithIdentifier:#"nameOfTheSegueBetweenOneAndTwo" sender:self];
Create a second method in the implemention of the first view controller with the following:
- (IBAction)returnToStepOne:(UIStoryboardSegue *)segue {
NSLog(#"And now we are back.");
}
This method will work to unwind any view controller back to this view controller. Notice that we implement the method in the view controller we wish to return to.
Go back to the storyboard. Focus in on the second view controller. If it is active, you should see a dark bar beneath it with 3 symbols on it. One of these is orange and when hovered over will show the name of the UIViewController subclass that this view controller represents. Control drag from this symbol woth the green symbol that means 'Exit'. You should see all available segue unwinds, which XCode automatically enumerates when you create segue unwind implementations inside UIViewController subclasses that you have shown on your stroryboard. Hence, you should see the segue 'returnToStepOne' as an option. Select it.
In your storyboard's document outline, find the section for the second view controller. You should see an item listed below it with a grey symbol that says something like "Unwind segue from ... to Exit." Click on this item.
Important and easily missed step follows!
On the right side of your storyboard, in the attributes inspector, you should see two fields. One for 'Identifier' and one for 'Action'. In most cases, the 'Action' field will have the text 'returnToStepOne:', which is what we want, but the 'Identifier' field will be blank. Fill this field with the text: 'returnToStepOne' (note that we leave out the colon).
Create a button on the second view controller and link it to an IBAction in its UIViewController subclass.
In the implementation for the method you just created, put the following code:
[self performSegueWithIdentifier:#"returnToStepOne" sender:self];
Run the application. You should now be able to unwind from the second view controller to the first.

How to move to second view programatically in ios app?

I have App with single storyboard, and two view in same story board. First one is controlled by ViewController and second one is controlled by View.(Two different class files, one inherits UIViewController and another UIView). App loads the first story board which is linked to UIViewController.
Now, I want to check some conditions in NSUserDefaults and skip the first view on app load if the condition is true. Skip first view can also be automatically load second view, this what I am trying to accomplish.
I have searched a lot and all of them were about the Navigation Controller, My views/controllers are not navigation controller, also I dnt want to use that because of the automatic navigation bar which I dont want.
Please help! Thanks.
remember to import the secondView,
and in storyboard you have to give the identifier "SecondView" to secondViewController
if ([[NSUserDefaults standardUserDefaults]boolForKey:#"Yes"]) {
SecondViewController *sv = (SecondViewController *)[self.storyboard
istantiateViewControllerWithIdentifier:#"SecondView"];
sv.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:sv animated:YES completion:Nil];
}

After using presentViewController existing segues can't be found

I am returning to my login view using the code below. The view loads correctly and everything looks fine. All buttons work etc.
JALoginViewController *loginVC = [[JALoginViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:loginVC];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
[self.navigationController presentModalViewController:navigationController animated:YES];
However, if a user tries to log in again, the segue that takes them to the next scene can't be found.
I'm using performSegueWithIdentifier if the users login credentials are correct, like this:
[self performSegueWithIdentifier:#"loginSegue" sender:self];
This is the error I receive:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (<JALoginViewController: 0x8d614b0>) has no segue with identifier 'loginSegue''
I've done lots of searching on Google and through the docs for the solution to this, the closet I've got (at least I think) is this question. The explain and solution sound like they could be correct and relevant, but I can't put them into practice.
Documents I've read and tried:
initWithRootViewController
popToRootViewController - The current root view controller is for a tab bar - not the login scene I need so as far as I'm aware I can't use this.
popViewControl
pushViewControl - This works to an effect, I don't think it is the correct way though. I don't want there to be navigation bar and I don't want my tab bar to appear when the user returns to the login scene.
I've tried various methods with limited / no effect. At this stage any help would be greatly appreciated.
Please let me know if I haven't provided enough information.
Thanks
JA
Edit - Zoomed out image of storyboard
![Zoomed out image of Storyboard][1]
On the basis of the screen snapshot of the revised question, from your rightmost red-highlighted scene, you should be able to:
[self.tabBarController dismissViewControllerAnimated:YES completion:nil];
and you'll be back at that initial screen (I'm assuming you did modal segue from initial screen to your tab bar controller).
Original answer:
If you want to manually push to a view controller, rather than creating it via alloc/init, you should use
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"loginsSceneStoryboardIdHere"];
or, if that view controller was the "initial" scene (the one with the simple arrow coming in from the left), you could use
UIViewController *controller = [self.storyboard instantiateInitialViewController];
And you shouldn't be manually creating the navigation controller, either. If the loginVC needs a navigation controller, you should embed that scene in a navigation controller right in the Interface Builder, then give that new navigation controller its own unique storyboard identifier, and then you can
UIViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"navControllerSceneStoryboardIdHere"];
[self presentViewController:controller animated:YES completion:nil];
I must confess that I'm worried by this whole "return to login via pushViewController" construct. I assume you know that you're not "returning" to it, but creating a new copy of it. If you push/modal from A to B and then B to C and then C to A, you're holding 4 views and their controllers in memory, two copies of A and one of B and one of C (which is, obviously, not good). I just wanted to make sure you don't have a circular set of segues and/or push/presentViewController references.
If the login is the initial scene in your app and if you've been doing only push segues (no modal segues along the way), you can do a:
[self.navigationController popToRootViewControllerAnimated:YES];
That will take you to the top level view controller, and it will pop off and release all of the intervening scenes.
If you're using iOS 6, you can avail yourself of the unwind segue, which can achieve the same functionality, but it doesn't care whether the preceding segues were pushes or modals.
There are lots of ways of skinning the cat, but generally doing a new presentViewController to the first scene in your storyboard is a very bad idea.

Moving from one view to another iOS

I'm relatively new to iOS development. I am to move from one viewController to another I use a modal segue transition on button click. This is a game so i want to allow the user to click images to essential move the the app menus.
I have a main page that displays several images, on clicking one i want to be able to move to another view. Currently doing this with a modal segue is causing odd problems with my touchesEnded event where if, for example, i navigate to a page 3 times the touchesEnded event is fired 3 times.
Is there a better way for me to do this or am i just missing thing fundamental?
Thanks
Yes, I think you must make the the navigation controller your root view controller then push views accordingly
UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:YOUR_BASE_CONTROLLER]
self.rootViewController = nav;
this is in your app delegate.
Then in your action method
[self.navigationController pushViewController:secondViewController animated:YES]
Im assuming you are using the Storyboard to link VCs using segues.
Modal segues are great for simple transitions but really seem to limit what you can accomplish when they are just linked through SB. Ive found that creating an IBAction that includes the following for a VC segue will allow you to not only control your segues more efficiently but also allow you to have a clearer view of what is actually occurring during the transition.
-(IBAction)goToVc:(id)sender{
//Other code to take place during the segue here
//This will identify the Storyboard in use
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
//This will identify the View Controller to switch to
SecondViewController *vc2 = [storyboard instantiateViewControllerWithIdentifier:#"SecondViewControllerID" ];
[self presentViewController:vc2 animated:YES completion:NULL];
}
Every time you perform a modal segue, you lose the UINavigationController that you were previously using. What you need to do is embed a UINavigationController in the view that you are performing a modal segue to.
Check out a question I answered the other day to help you visualize more clearly what I'm talking about.

Resources