How to switch views using UIStoryboard and UIViewcontroller - objective-c

I'm still pretty new to Obj-C and iOS so bear with me. In my app I am trying to implement a share button that brings up a second view in the current view controller. I'm following this tutorial(http://www.youtube.com/watch?v=DZ3SyGInklQ) and I run into a problem where the dev uses initWithNibName and I am using a storyboard. I'm wondering why my second view is not coming up when I press my button. It's probably very obvious but I can't figure it out.
Heres some of my current code:
Menu.h
//Share button
- (IBAction)shareButton:(id)sender;
Menu.M
- (IBAction)shareButton:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MenuStoryboard" bundle:nil];
UIViewController *sharebuttonview = (UIViewController *)[storyboard instantiateViewControllerWithIdentifier:#"sharebuttonview"];
[self presentViewController:sharebuttonview animated:YES completion:NULL];
}

First you go into the storyboard and then you connect the Share Button with the View you want to show. After that you name this segue with an Identifier.
In you Menu.M in the IBAction you write:
[self performSegueWithIdentifier:#"mySegueIdentifier" sender:self];
(mySegueIdentifier is the Identifier you used before)

Based on your description of the issue it appears that you may want to do a manual segue, which allows you to open a target view controller from any number of UI controls. The workflow has changed from Xcode 5 compared to prior versions of Xcode. You may want to see my blog post for additional tips but essentially you will want to open your storyboard and do a Ctrl+Drag from one view controller in the document outline view to a second view controller.
Then you will need to name the segue that is created by clicking the Segue in the middle of the gray line connecting the two view controllers and update the segue id in the identity inspector.
In your source view controller you should be able to have any action call [self performSegueWithIdentifier:#"MySegueID"];
Additionally, you can add a prepareForSegue method to the source view controller, which allows you to initialize and pass information to the target view controller.
Apple has a sample project that you can download to see this workflow in detail (MultipeerGroupChat)
Hope this helps.

Related

Scene is unreachable due to lack of entry points... Custom Button

I'm new to programming on xCode. I've made a login screen in a snapchat format. Currently, I started with two view controllers one for login and then signup but I changed it so I start with an intial view controller that has two custom buttons I made. View the picture. I want it to be that so when you clean the login button it takes you to the login screen and when you click the sign up button it takes you to the sign up screen.
I'm not sure what I'm doing wrong. I want![enter image description here][1]
My app delegate has the following:
http://i.stack.imgur.com/8fWT4.png
http://i.stack.imgur.com/b9mfN.png
I just don't understand as to why I keep getting the following error: Scene is unreachable due to lack of entry points and does not have an identifier for runtime access via -instantiateViewControllerWithIdentifier:.
Unless your segueing to the view in question, you would need to give it a storyboard identifier to connect the nib with the related class. Go into the storyboard and ensure you've set the class and storyboard id. If you're segueing to the class, ensure you give your segue an identifier. But if not, you can then do something like:
YourViewController *vc = (YourViewController*)[self.storyboard instantiateViewControllerWithIndentifier:#"YourStoryboardIdentifier"];
[self presentViewController:vc animated:YES completion:^{}];// Or however you want to present it. ie pushing onto the navigation stack
You can use this code:
WaitingRoomVC *ivc=[self.storyboard instantiateViewControllerWithIdentifier:#"waiting"];
[self.navigationController pushViewController:ivc animated:YES];

view controllers: presentation, dismissal

Just for the purpose of learning some particular aspects of xCode, I am creating a simple app that has 2 functional view controllers. Each contains a button that can be pressed to switch to the other. I am not using segues. I am using pointers retrieved from the app delegate.
visual illustration (click for higher resolution):
When the app loads, the root view controller presents view 1. When you click "switch to view 2," the following code causes view 2 to appear:
- (IBAction)buttonPressed:(id)sender
{
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
[self presentViewController:appDelegate.view2 animated:YES completion:nil];
}
So far, so good.
But when you click "switch to view 1" on the second view, this same code (replacing "view2" with "view1") gives the following error:
Application tried to present modally an active controller.
So to summarize (where --> = presents), we have root --> view1 --> view2 -x-> view1
I don't care about retaining the history of who presents whom. I simply want the buttons to bring to the top (make visible) a previously displayed view controller, maintaining the state of its views.
It would be nice to know the following:
Is there a workaround that would enable me to achieve the intended behavior using presentViewController? E.g., root --> view2 --> view1
What other method(s) would be more practical for achieving the desired behavior? It/they must use the app delegate because in my real application that will be unavoidable.
Am I breaking the rules by trying to put a view controller on top without integrating into some larger architecture? E.g, is this sort of behavior supposed to be handled by navigation conrollers and pushing/popping? If so, can you explain why xCode doesn't want me to do this? Why can't I just display whatever view controller I want, without it necessarily having any relationship to other view controllers? (Maybe because that could lead to abuse of the app delegate?)
What does it really mean to "present" a view controller? What functional limitations or capabilities does it entail beyond creating pointers between presenting and presenter? What is the importance of leaving the presenting view controller "active"?
If instead make the button on view1 send the presentViewController message to the root view (which I hoped would just change the presentation chain from root --> view1 to root --> view2, leaving view1 still existing in memory but not part of this chain), I get a different error: "Attempt to present on whose view is not in the window hierarchy!" What does this mean? I can't find an explanation of window hierarchy.
Okay, I know I'm asking a lot here, but any amount of enlightenment will be greatly appreciated!!
The correct way to do this is to get the underlying rootVC to do the presenting and dismissing (as you attempt - without the dismissing part - in point 5). You can achieve this by sending a message + completion block back to the rootVC from each of view1 and view2 when you want to present the other.
When you are in view1:
- (IBAction)buttonPressed:(id)sender
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
UIViewController* presentingVC = self.presentingViewController;
[presentingVC dismissViewControllerAnimated:YES completion:^{
[presentingVC presentViewController:appDelegate.view2
animated:YES
completion:nil];
}];
}
and similarly for view2. Take care that you need this line:
UIViewController* presentingVC = self.presentingViewController;
as you can't refer to 'self.presentingViewController' inside the completion block as it's controller has been dismissed at this point.
I think that answers points 1 and 2.
To answer point 3 "Why can't I just display whatever view controller I want, without it necessarily having any relationship to other view controllers?" - well you can (via the rootViewController property of the window), but then you are going to have to implement navigation and manage your viewController pointers, which means you will end up creating a controller of some sort. Apple is helping you here by providing you with a few which cover most needs.
As regards your point 4 - the presenting of a viewController is controlled by the presenting VC, which is why you want to keep that one 'active'. When you send this message:
[self dismissViewControllerAnimated:completion:], self just reroutes the messge to it's presentingViewController. If you get rid of your presentingViewController your dismiss method will break.
Point 5 is answered above. You need to dismiss the topmost view first before asking an underlying view to present. Note that view1 is "still in memory" but only because you have retained a pointer to it in your app delegate.
update
As you are trying to get this to work with an initial launch-straight-to-view1, you could make a BOOL launched property and check/set it from your rootViewController's viewDidAppear:
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (!self.launched) {
self.launched = TRUE;
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
[self presentViewController:appDelegate.view1
animated:YES
completion:nil];
}
}
Let me try to tackle your points one by one.
1) No, you shouldn't do this all with presentViewController.
2) If you want to do root --> view1 --> view2 --> view1, then you don't do that all with presentViewController. To go from view1 back to view2 you should use dismissViewControllerAnimated:completion.
3) The view controllers do have a relationship when you use presentViewController:animated:. The presenting controller has a pointer to the one it presents, and the presented one has a pointer to the one that presented it. So, you're getting these relationships whether you want it or not. There is a way to display whatever controller you want with no relationship between them -- just reset the window's root view controller. The old view controller will be deallocated (if you don't keep a strong pointer to it), and the new one becomes the window's root view controller.
4) Presenting a view controller makes that controller a modal view controller -- it takes over the whole screen and is intended to be used as an interruption in the flow of the app. You really shouldn't use them extensively to go from one controller to another (and especially not for going "backwards" to previous controllers). Because of the way it's supposed to be used, you normally want to go back to the controller that presented it, so that's why it's kept "active" (in the sense that it's not deallocated).
5) You get that error because root's view is not on screen, view1's is. You need to present a view controller from the controller on screen.

UINavigationController UIToolBar does not show up in my views

My UINavigationController contains a UIToolBar with 3 UIBarBottomItems - It has all been drag/drop designed in the storyboard. I want this UIToolbar to be shared on all my views. I have therefore set checked the "shows toolbar". But when I run it the UIToolBar is empty in all of my views. What could be the reason for this ?
I realize this is an old thread but I've just been struggling with this for a couple hours and finally figured out what was wrong. It was something simple so thought I would share. I was calling [self.navigationController setToolbarHidden:NO]; in viewDidLoad. The problem was that viewDidLoad is called before the view controller is pushed onto the navigationController so self.navigationController is nil. I moved the code to viewWillAppear: method and it worked.
UINavigationController have default toolbar. which you can use. you can use following code
[self.navigationController setToolbarHidden:NO];
in the topmost view controller and
[self setToolbarItems:items];
in all your view controllers, where items is an NSArray of that view controller's toolbar items.
select your initial view controller in the storyboard and embed it in navigation controller.
now all your pages should have the navigation bar.. if u manually dragged dropped the previous bars when u run the program it'll show both...
You'll have to remove the old ones and then modify the new one as required.

Preventing the dismissal of a view controller in a segue

I am using StoryBoards and am trying to overlay a View Controller's view on top of another View Controller's view so that the two are visible (the top one has a couple of transparent areas).
If I connect the two together with a modal Segue and then call [self performSegueWithIdentifier:#"showTutorial" sender:nil]; the source view is removed and the destination one is shown. No joy.
If I connect them with a push Segue, calling [self performSegueWithIdentifier:#"showTutorial" sender:nil]; doesn't bring up the new view. Embedding the source view controller in a Navigation Controller brings up the destination view, but also removes the source view. No joy.
Any suggestions?
#Inafziger: I thought I would have been able to do that with a segue, but segues are not the way. Also, as I wanted to keep working with the Storyboard and avoid making a new nib file from scratch, here's what I did:
tutorialView = [self.storyboard instantiateViewControllerWithIdentifier:#"Tutorial"];
[self.view addSubview:tutorialView.view];
Then in the Storyboard, write "Tutorial" in the ViewController's Identifier field.

how to implement didSelectRowAtIndexPath in table view in Xcode 4.2?

SliderDemoController *sliderDemoController=[[SliderDemoController alloc] initWithNibName:#"" bundle:nil];
[self.navigationController pushViewController:sliderDemoController animated:YES];
i implemented this method using storyboard. but this method is not working. i want to open new controller in table view cell.
If You want to access any view controllers which is in story board then you should use UIStoryBoard class.If you not sure about how to do that so, Here is the link for apple document about UIStoryBoard and use the method + (UIStoryboard *)storyboardWithName:(NSString *)name bundle:(NSBundle *) storyboardBundleOrNil to access your storyboard.
Access your view controller with the method - (id)instantiateViewControllerWithIdentifier:(NSString *)identifier and use the returned view controller object.Hope this helps you....
You don't need to query the UIStoryboard object -- setting up transitions between view controllers is what storyboards do automagically. And with storyboards, you don't need to implement tableView:didSelectRowAtIndexPath: either.
If you haven't already, define a segue from the (prototype) table cell to the destination view controller (looks like that's SliderDemoController for you) by control-dragging. (Choose the Push segue type.) For functionality equivalent to the non-storyboard code you posted, that's all there is to it -- now tapping any row in the table will push in a SliderDemoController.
However, you probably want to configure that SliderDemoController based on which row was selected, right? Then, in your table view controller, implement prepareForSegue:sender:. There you can get a reference to the destination view controller (from the segue parameter) and set it up however you like.