How to open my UINavigationController programmatically? - ios

One of the things I don't like about WYSIWYG/visual programming, is when you get to a point where you need to step outside of the box, you're left scratching your head. I'm at such a point right now along my iOS learning curve.
I have a custom UICollectionView thing. In two places (create and edit points), I need to present a list to the user to enable/disable (select/deselect) items from a list. So I go to the storyboard and whip up something like this:
In the past, following tutorials, I would control-drag a link from some control to the NavigationController show in the middle, I would tell it was a modal segue, tune a couple of methods, and get an arrow connecting the two for my efforts.
But in this case, I don't have obvious points to start that action from. I do have a + button. But it needs to do some other things first, and if all is well, then programmatically initiate the open, and somehow get notified of the state when it returns. Same for the individual cells, they might want to configure my table controller, and then open it, and be notified when it closes.
So I'm looking for a recipe of how one does this, what the key methods I should be looking for are. Apple's docs are great for reference, but I find figuring out how to do something from scratch difficult.

After creating a segue in your storyboard, you can initiate a segue any time programmatically by calling
[self performSegueWithIdentifier:#"segueID" sender:person];
Where "segueID" is a string you set for your segue in interface builder in the Identifier field in the identity inspector (right menu panel, 4th tab).
The segue does not need to be created from a control, you can just create one directly from one view controller to another. I usually do this on the right side menu by right-clicking on one view controller object and dragging to another one. This way, it acts as a segue that you can initiate programmatically any time you want.
As for getting notified when you come back to a view controller, (unless I'm misunderstanding your question) you can use either:
(void)viewWillAppear:(BOOL)animated
(void)viewDidAppear:(BOOL)animated

Create a UINavigationController programmatically with a desired view controller set as a root view controller. Here is an example of what you could put in a method invoked when user taps the plus button:
UIViewController *vc = [[UIStoryboard storyboardWithName:#"YourStoryboardName" bundle:nil] instantiateViewControllerWithIdentifier:#"YourViewControllerID"];
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:vc];
[self presentViewController:nc
animated:YES completion:nil];
To get a state, or information about the selected items you can use Delegation and declare a protocol. Example:
#protocol YourSampleDelegate <NSObject>
- (void)didSelectItem:(NSObject *)item;
#end
Then, your view controller (the one with the plus sign) should implement this protocol:
#interface ViewController : UIViewController<YourSampleDelegate>
...
#end
#implementation ViewController
...
#pragma mark - YourSampleDelegate conformance
- (void)didSelectItem:(NSObject *)item;
{
// Do something with the item.
}
#end
You also have to create a delegate property in a view controller with collection view and set the view controller with a plus as a delegate. There are tons of examples on the Internet. I hope this shows you the right direction.

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.

Storyboards create modal view accessible from anywhere

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.

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];
}

Dismissing/Delegate second view in a modal stack in storyboard

I have a TableView which describes a book with sections which represents the chapters and rows representing the verses.
A the top of this TableView I have a button in a navigation bar to allow "navigation".
The goal of this navigation button is to allow the user to easily jump to a given chapter/verse without scrolling manually (which can be very long).
When the button is pressed a tableview controller is called displaying all the available chapters of the book and when a chapter is selected another table view is called displaying a list of the available verses in the current chapter. Finally when the line is chosen the tablew view displaying the book should scroll to the given index/row.
So the idea : from the tableview representing the book I call the chapters view as modal and the verses as a push over the chapters view.
My problem is that I don't get the point of managing the delegate and dismissing from the 2nd modal view.
With 1 modal view I do things like that.
In the displayed VC (View Controller) I added the protocol and the delegate
#protocol ChapitresTableViewControllerDelegate <NSObject>
- (void)didDismissPresentedViewController;
#end
#interface ChapitresTableViewController : UITableViewController
#property (nonatomic, weak) id <ChapitresTableViewControllerDelegate> delegate;
#end
I have in the didSelectRow
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate didDismissPresentedViewController];
}
in the displaying VC I add the following line
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
ChapitresTableViewController *chapitresTableViewController = segue.destinationViewController;
chapitresTableViewController.delegate = self;
}
and of course
-(void)didDismissPresentedViewController
{
[self dismissViewControllerAnimated:YES completion:nil];
}
this would just work fine if I wanted to close after the first modal VC, but what I want is to have the second one being dismissed after I click in the second. Ok I can write the protocol and stuff in the second modal VC but how do I manage to have the delegate being send to the second VC.
Hope my question is clear enough it is not so easy to explain it.
Anyone understand me and can help me ?
NOTE : I know for now I don't pass any parameters back to the delegate, which I will do later to do the scroll. For now I just want to be able to close the second view, then I will add the required stuff to pass the parameters back to the delegate
I'm sure you can do this, but rather than modal view controllers with a navigation bar, wouldn't it be easier to use a navigation controller? Then you can use popToViewController to go back as many levels as you want to a particular view controller. You can either pass the UIViewController* of the various controllers you might want to pop to, or do so programmatically: e.g. How to pop back to specify viewController from navigationController(viewControllers/stack)?
In this scenario previous views controllers are retained. The ones you pop off are released (just like the modal ones you dismiss are released), but the ones that you pushed from are retained (just like the ones you presented from in a modal world are retained).
If the book is large, though, you'll have to be sensitive to memory usage. Thus, you will probably want to handle didReceiveMemoryWarning to release the model data for the previous views in either your modal sequence or push sequence, in which case, on viewDidAppear, you'll want to see if your app had to release the memory in response to didReceiveMemoryWarning and reload it in that case. But that's the desired behavior, either way, gracefully release the pages if needed (and reload them when the particular view reappears), but keep it in memory if you can.
Finally, you might also want to contemplate using UIPageViewController. Given what you've described, I'd like consider UIPageViewController first, UINavigationController and push segues second, and the use of modal segues third.

Resources