Okay, so far I've two view controllers in my storyboard. One with "login" elements and other as "User's home" sort of thing. I am intending to do the following : When user clicks on login, there's a bit of processing and then it should show to user's home screen..
When I do it via storyboard, i mean = control drag "login" button to user's home view it works fine. But I cant use that as I've to process the login data. It also shows some animation meanwhile. So, I've to do this shift programmatically. I wrote following code in the login button's IBAction ::
HomeViewController *homeView = [[HomeViewController alloc] init];
[self presentViewController:homeView animated:YES completion:NULL] ;
Now, this takes user to the intended view. However, the elements in the homeview (say a label, navigation bar are not being shown. And thats what my worry is.
(In theory, I can build entire view programatically but i think thats not the proper way of doing this, is it ? I want to make use of storyboard functionality in full i.e. design maximum UI in storyboard and use them from the backend how you want them to work.)
How do I do it ?
Cheers.
PS : I intend to add few more view controllers so at the moment i didn't think of navigation controller. not sure, if i should use it.
Using storyboards you should be using:
UIViewController *homeView = [self.storyboard instantiateViewControllerWithIdentifier:#"someID"];
[self presentViewController:homeView animated:YES completion:NULL] ;
Then set the ID to the view controller in storyboard like so:
Additionally, if you wish to there is absolutely nothing wrong with designing your UI entirely in code. Personally I prefer it. It gives you much more flexibility than interface builder.
In addition to NSPostWhenIdle's suggestion of instantiateViewControllerWithIdentifier, you can also define a segue between the two view controllers (not between the button and the second controller, but between the two view controllers):
Then give the segue a unique identifier, and then have your IBAction method do a performSegueWithIdentifier. This way your storyboard will continue to visually represent the various relationships between your view controllers.
Related
I am developing an application with iOS 9 based SDK , this is my first time I am working with Storyboards , I have 20 view controllers, each scene has Next / Previous buttons to go back and forward . I have a huge problem with going forward !. If I move from scene 1 to for example to scene 15 I received memory warning and then application crashes . I have searched and it seems there is method called unwind segue but it seems this is for going back ! it's something like dissMiss method .
I connect each scene with line in Interface Builder :
Here is segue's setting :
I would be grateful if you help me out .
EDITED :
I tried to present a view controller programmatically but result was the same ! .
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
WhatIsDino *vc = (WhatIsDino*)[mainStoryboard instantiateViewControllerWithIdentifier:#"WID"];
[self presentViewController:vc animated:YES completion:nil];
Seems like it's a problem of wrong approach, and not the storyboard.
Let me guess, since before storyboard you used to change your app's rootViewController to the next/previous screen once you tap on the arrow button. So previous screen are released and deallocated from memory once you set a new rootViewController.
And now you're presenting every next view controller modally, which involved creating new UIWindow and loads all the hierarchy of you screen and keeps previous underneath the new one so it holds the memory and you're getting out of memory crash.
Well, you can do rootViewController approach with a storyboard too since it's just another way to manage your screens while development. Storyboard offers additional features like segues, static table view cells, general tint color and so on. [UIStoryboard -instantiateViewControllerWithIdentifier:] is the method you might find interesting.
But I'd rather recommend you to check out the UIPageViewController, it's like a container for the screens. Unfortunately, it cannot have the segues to your scenes (because of the special way segues work) so you have to use -instantiateViewControllerWithIdentifier: method anyway. You can treat inner view controllers of UIPageViewController as you do with rootViewController before.
You can also navigate without segue and Its easy way I think.
If you want to navigate from Class1 to Class 2 then follow these steps.
1) In Class 1, Import Class2.
2) In your button Action, Write this code.
Class2 *next = [self.storyboard instantiateViewControllerWithIdentifier:#"Class2 Identifier name"];
[self.navigationController pushViewController:next animated:YES];
Do not forget to give Identifier name in story board that is "Storyboard ID" in Attribute inspector of particular class.
No need to add Segue,Your storyboard would look clean.
The problem is that you are adding view controller after view controller with modal presentation. That causes each view controller to be added on top of the previous one, and all of them accumulate, using more and more memory.
Using a navigation controller and a push also piles the view controllers on top of each other.
You will have this problem if you use storyboards, nibs, or create the view controllers manually.
If you have a design where the user can move through a large series of view controllers then you probably want to dismiss the previous one before pushing/presenting a new one.
You can probably dismiss the previous view controller without animation and then present the new view controller each time you want to display a new one and avoid the memory issue. i'd have to experiment with it to get the effect I was after, but that's what I would suggest.
I am trying to write an app using UINavigationViewController. My first screen has several buttons on it, and on the click of each button, I want to segue to a UIViewController. I know that I can add a segue on each button, all pointed to the UIViewController that I want to go to, but I was wondering if it is possible to use only one segue that can be fired from each of the buttons.
If that is not possible, I was wondering if it was possible to open the second UIViewController from the first one, on button click, and provide a Back button like the UINavigationView provides. I did manage to get everything on this idea working, except for the back button. I mean I can put a standard button somewhere on the screen and go back, but I'd like the standard back button on the UINavigationView.
Phew! I'm not sure if that makes any sense.
I know that I could also use a tableview, but I'm trying to set this up with buttons.
Thanks
Edit: Thank you to everyone that answered. I now have this working. I would vote up the answers, but I don't have enough posts to do it. I appreciate the answers!
If you need to have separate action functions for each button, suggest that you segue from the main controller to the other controller and create a segue identifier (see xcode procedure below); then, use performSegueWithIdentifier from each of the button action functions. You can also take advantage of the prepareForSegue. To create the segue, control-drag from the left button in the controller in the storyboard to the controller you want to segue to and pick show.
Check the example code in swift that I did for a very similar problem in the SO reference
Linking View Controllers through button
You can embed the main controller in a navigation controller and that will give you the ability to navigate back. If you have multiple layers you can also use unwind segue.
Link each button to one single action (ex. buttonClick) in that ViewController and then perform the appropriate segue using pushViewController method on self.navigationController
-(IBAction)buttonClick:(id)sender {
if(sender.id == self.button1) {
DestinationViewController *vc = [[UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:#"VC_IDENTIFIER"];
[self.navigationController pushViewController:vc animated:YES];
}
Or if you already have that 1 segue defined in storyboards you can use
[self performSegueWithIdentifier:#"SegueIdentifier" sender:self];
And use that inside the buttonClick method. Using the 1st example, or the second one as long as the segue you setup in the storyboards is a push then you should already get the back button as that is the default behavior for pushing view controllers onto the navigation stack.
Alright I'm really failing to see what the big win in having Navigation Controllers wrap my views and trying to drag segues on my Storyboards are. Sure you get the benefit of iOS automatically adding a back button as you push/pop views off the stack, but for anything past a simple app, I don't even care for that!
My goal is simply to have 1 view actually represent a given page. Then just programatically move to another view using:
ViewController *vc = [storyBoard instantiateViewControllerWithIdentifier:#"ViewController"];
[self presentViewController:modalYearPickerViewController animated:NO completion:nil];
or
ViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
[self.navigationController pushViewController:vc animated:YES];
I realize that in order to push with the second example I'd need the view to be wrapped in a Navigation View Controller, however using one of these methods prevents my from ever having to create "segues" which I find hard to manage. Half the time when I setup a segue iOS throws an error saying it cannot perform or the segue doesn't exist.
A lot of the time I'm either hiding back buttons or on the fly changing where "back/return" may drive the user based on previous actions or screens.
Anything massive I'm missing here? I am fairly new to iOS but I come from the web world where I'm used to being able to navigate around screens with ease.
Anyone have any thoughts?
EDIT: Here is a dead simple example solution. When I get to the "details" page I want to have a back button to the home page instead of the modal.
http://andrewherrick.com/spike/nav_ios.zip
From your diagram, I'd expect:
At the root, you have a navigation controller which contains the Artists. Artists has a modal segue to New Artist (well, to a nav controller containing it) and a push segue to Artist Songs.
New Artist is the root of a navigation controller and has a push segue to Artist Songs. New Artist has a Cancel and a Done button in the navigation bar.
Artist Songs should be configurable (it could determine this itself), such that it has a back button (always based on this model, and automatically handled) and a Done button when it is pushed from New Artist (which completes the save and dismisses the modal, thus taking the user back to Artists).
All of the above is a achievable either with segues or direct instantiation and transition from code, which you use is a matter of personal preference.
I need to create a modal "flow" within my app. It is made of two "scenes", these are both UITableViewController subclasses.
The user will be able to push and pop between these two table views.
At any point they will be able to press "Done" (in a nav bar) and dismiss the entire modal view to go back to where they were.
This whole modal flow needs to be accessible from several places in the app. I don't really want to create multiple modal segues to this.
My question is, creating this in a storyboard, would you create a whole new storyboard for this flow (I don't like this).
Would you just create multiple modal segues?
Should I create this flow in the same storyboard file but as a separate entity accessible by the identifier?
Or something else?
Sounds like it would be easier to use a single storyboard, but not create multiple segues everywhere. You can programmatically present the view controller pretty easily:
MyViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"MyViewController"];
// set any properties on vc here, if necessary to pass it any data
[self.window.rootViewController presentModalViewController:vc animated:YES];
You could place all this code in a helper method to reuse this code more easily, maybe a class method like this:
#interface MyViewController ...
+ (void)presentNewViewControllerModally;
...
#end
Tapping the done button:
[self.window.rootViewController dismissModalViewControllerAnimated:YES];
Note that if there's a good chance you'll never see this modal view controller, you could place that view controller in a separate xib file instead of in the storyboard, and I think that could make things more efficient (storyboard remains more lightweight). In this case, just replace the instantiteViewControllerWithIdentifier message above with:
[[MyViewController alloc] initWithNibName:#"SomeNib" bundle:nil];
...and the rest of the code is the same. I've used this technique for a "login" view controller that would only occasionally need to be presented.
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];
}