Using a segue from a UIViewController with UItextfield to populate a UITableViewController - objective-c

Yes I am new to Xcode and coding in general. I did a bunch of research and figured out how to go from UItableviewcontroller to the viewcontroller then using the "unwind segue" to populate the table, which is not exactly what I want.
I would like the initial scene to be the viewcontroller rather than the table and as such the unwind segue isnt working. I've been trying to rearrange things for days but to no avail.
Any help would be greatly appreciated.
ViewController.m
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.saveButton) return;
if (self.labelField.text.length > 0) {
self.toDoItem = [[YYTData alloc] init];
self.toDoItem.itemName = self.labelField.text;
TableViewController.h
#interface YYYTableViewController : UITableViewController
- (IBAction)unwindToList:(UIStoryboardSegue *)segue;
Tableviewcontroller.m
- (IBAction)unwindToList:(UIStoryboardSegue *)segue
{
YYYFirstViewController *source = [segue sourceViewController];
YYTData *item = source.toDoItem;
if (item != nil) {
[self.toDoItems addObject:item];
[self.tableView reloadData];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.toDoItems = [[NSMutableArray alloc] init];
[self loadInitialData];

Segues are used to navigate through viewControllers that are connected in a UINavigationController stack. To have viewControllers added to this stack, you have to first manually create segues in storyboard. You can access the viewControllers in your navigation stack with methods such as performSegueWithIdentifier:. In order to have your viewController be the first viewController in your navigation stack, do the following in storyboard:
1.) Delete all viewControllers that you have.
2.) Drag and drop a UINavigationController.
3.) Drag and drop a UIViewController (will be your first viewController and I will refer to it as viewController).
4.) Set the class of viewController to the class of your view controller.
--This is done by clicking on the viewController (in the left panel are of storyboard) and navigating to the identity inspector (in the right panel area of storyboard) and entering the name of the viewCotroller's class.
5.) Now you set the rootViewController: of navigationController to viewController by clicking on the navigationController (in the left panel area of storyboard), then looking in the connections inspector (last icon in the right panel of storyboard). Here you will see rootViewController, you'll right click from rootViewController and drag a line from it to your viewController (in the left panel of storyboard).
After completing these five steps, you can add a tableViewController in storyboard create a segue for it, and everything should work as you'd like it to.

Related

Perform segue from main view on container view

I seem to be unable to understand how to go about this. I have a button on my main view. This view contains a container view. I would like the button on the main view to make the container view segue to another view. I have set up an identifier for the segue, which goes from containerView1 to containerView2. This is a push-segue. The identifier is pushSegue.
On the button on the main view I have tried this:
- (IBAction)btnChangeLocation:(UIButton *)sender {
UIViewController *a = [[ContainerView1 alloc]init];
[a performSegueWithIdentifier:#"pushSegue" sender:nil];
}
I have successfully performed this segue from within containerView1, by just placing within it, and performing the segue from there. It works just fine then.
- (IBAction)testButton:(UIButton *)sender {
[self performSegueWithIdentifier:#"pushSegue" sender:nil];
}
But how would I go if I wanted to trigger the segue on the containerView1, from the button on the main view?
Thanks.
EDIT:
I would also like to be able to perform the same segue, from a container view, that is within the container view.
Just to summarize.
MainView----->ContainerView1-->pushSegue--->ContainerView2
ContaainerView1 has a subContainerView, which also has a button, which causes ContainerView1 to segue into ContainerView2. This button and the button on the MainView does the same thing really, just from different "locations".
EDIT: Added a picture to help explain. http://tinypic.com/r/maxpp2/8
With UIViewController *a = [[ContainerView1 alloc]init]; you are instantiating a new ContainerView1 controller. That won't help you; you need to call performSegueWithIdentifier:sender: on the instance already created.
Depending on how your Storyboard and code are set up, you need to find a way to get a hold of the embedded view controller.
For this set up:
You could do something like this in the main (hosting) view controller:
#property (weak, nonatomic) IBOutlet UIView *childView;
#property (weak,nonatomic) UINavigationController *container;
...
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"embedContainer1"]) {
self.container = segue.destinationViewController;
}
}
-(IBAction)doIt:(id)sender {
[self.container.viewControllers[0] performSegueWithIdentifier:#"pushSegue" sender:nil];
}
By implementing prepareForSegue:sender:, you're able to get a reference to the child viewcontroller; cleaner then going through the array of childViewControllers IMHO.

Remove view controller from another view controller

I am very new to iPhone app development.
I am developing one example application for iPhone emulator using Objective-C++ and std CPP.
I have two views in my application, on some events from CPP code i am displaying second view using following code from the first view controller.
// Defined in .h file
secondViewScreenController *mSecondViewScreen;
// .mm file Code gets called based on event from CPP (common interface function between Objective-C++ and CPP code)
mSecondViewScreen = [[secondViewScreenController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:mSecondViewScreen animated:YES];
I am able to see second view coming on screen, but problem is that i am unable to end/remove second view controller from first view controller.
How can i remove second view controller from first view controller using second view controller's pointer or using any other method.
To remove second view i have following code in second view controller file, which gets called on button click event of second view.
// In .mm of second view controller.
- (IBAction)onEndBtnClicked:(UIButton *)sender
{
[self dismissModalViewControllerAnimated:NO];
[self.navigationController popViewControllerAnimated:YES];
}
Above code works perfectly, when i click on the seconds view's end button it removes the second view controller from the screen and navigets to first view, how can i use same code to remove second view from the first view controller.
I tied to use NSNotificationCenter to send event from first view to second view to call the function onEndBtnClicked but it is not working.
What is the proper way of doing it?
OSX version: 10.5.8 and Xcode version: 3.1.3
In the secondViewController create a protocol like:
#protocol SecondViewScreenControllerDelegate <NSObject>
- (void)secondViewScreenControllerDidPressCancelButton:(UIViewController *)viewController sender:(id)sender;
// Any other button possibilities
#end
Now you have to add a property in the secondViewController class:
#property (weak, nonatomic) id<SecondViewScreenControllerDelegate> delegate;
You sinthesize it in the secondViewController implementation:
#synthesize delegate = _delegate;
Finally all you have to do is implement the protocol in your firstViewController and set the secondViewController properly prior presenting it:
#interface firstViewController : UIViewController <SecondViewScreenControllerDelegate>
...
#implementation firstViewController
- (void)secondViewScreenControllerDidPressCancelButton:(UIViewController *)viewController sender:(id)sender
{
// Do something with the sender if needed
[viewController dismissViewControllerAnimated:YES completion:NULL];
}
Then when presenting the secondViewController from the first:
UIViewController *sec = [[SecondViewController alloc] init]; // If you don't need any nib don't call the method, use init instead
sec.delegate = self;
[self presentViewController:sec animated:YES completion:NULL];
And ready. Whenever you want to dismiss the secondViewController from the first, just call: (inside the secondViewController implementation)
[self.delegate secondViewScreenControllerDidPressCancelButton:self sender:nil]; // Use nil or any other object to send as a sender
All that happens is that you send a pointer of the secondViewController that you can use from the first. Then you can work with it without problem. No C++ needed. In Cocoa you won't need C++. Almost everything can be done with Objective-C, and it's more dynamic.
If there are only two views in your application then use
- (IBAction)onEndBtnClicked:(UIButton *)sender
{
[self dismissModalViewControllerAnimated:NO];
}
remove line below:
[self.navigationController popViewControllerAnimated:YES];
as it is you are dismissing second view then why you want to remove it from first view.

SideMenu black view

I am trying to make a sidebar menu but i have a little problem.
I explain :
I created an UIViewController that i called sideMenuViewController
In my viewController Class (the initial view controller), in the header file, i import my class SideMenuViewController and i wrote :
-(IBAction)openSideMenu:(id)sender;
#property(nonatomic, retain) SideMenuViewController *sideMenu;
The openSideMenu action is associated to the menu button.
I implemented this method like this :
- (IBAction)openSideMenu:(id)sender {
CGRect destination = self.view.frame;
if(destination.origin.x > 0){
destination.origin.x = 0;
}else{
destination.origin.x += SideMenuX;
}
[UIView animateWithDuration:0.4 animations:^{
self.view.frame = destination;
}completion:^(BOOL finished) {
if(finished){
}
}];
}
SideMenuX is a macro : #define SideMenuX 154.4
My viewDidLoad method looks like this :
- (void)viewDidLoad
{
[super viewDidLoad];
_sideMenu = [[SideMenuViewController alloc] init];
[self.view sendSubviewToBack:_sideMenu.view];
// Do any additional setup after loading the view, typically from a nib.
}
The problem is that when i click on the menu button, i get a black screen and not my side menu view.
Thank you in advance !
Two problems:
You are not adding the sideMenu at all. Try adding it to the parent view (self.view.superview), which in your case most likely will be the UIWindow: [self.view.superview insertSubview:_sideMenu.view belowSubview:self.view]; If you are using a navigation controller, use self.navigationController.view instead self.view.
Not sure if you initialized the view with a NIB or the Storyboard (see below if you didn't).
Here is a working example. I created the left view controller inside the storyboard like this:
Throw a View Controller component on the storyboard.
Select the controller on the left column, and go to the Identity Inspector on the right column (alt+cmd+3):
Set the Class to SideMenuViewController
Set the Storyboard ID to SideMenuViewController
Instantiate the controller inside viewDidLoad with
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
self.sideMenu = (SideMenuViewController*)[storyboard instantiateViewControllerWithIdentifier:#"SideMenuViewController"];
then insert it as child of the superview.
(Answering the comment below)
This line is the problem:
[self.view.superview addSubview:_sideMenu.view];
In a NIB based project the superview is UIWindow, but in a Storyboard project, the self.view.superview of a UIViewController is nil. You can solve this, for example, adding a UINavigationViewController. Follow these steps:
Throw in a "Navigation Controller"
Delete the view controller it points to.
Press Ctrl and drag the pointer from the UINavigationController to your view controller, and select "root view controller" on the dialog that appears.
Drag the arrow pointing to your view controller to the UINavigationController (the one that marks the initial view controller, not the one that comes from UINavigationController).
Then change your code to
_sideMenu = [[SideMenuViewController alloc] initWithNibName:#"SideMenuViewController" bundle:nil];
[self.navigationController.view.superview insertSubview:_sideMenu.view belowSubview:self.navigationController.view];
To hide the navigation bar of the UINavigationController, select it in the Storyboard and click Hidden in the Attributes Inspector (alt+cmd+4).
All you're seeing is black because you don't have the side menu view added. Try this:
- (void)viewDidLoad {
[super viewDidLoad];
_sideMenu = [[SideMenuViewController alloc] init];
[self.view addSubview:_sideMenu.view];
[self.view sendSubviewToBack:_sideMenu.view];
}

How to presentModalViewController without dismiss the TabBarController

Hey guys i`m trying to present a modal view controller inside an application with a tab bar controller. The problem is, every time the new view is presented, it on top of my tab bar.
I need to keep my tab bar even when the view is presented. Like google maps application does with his toolbar at the bottom of the screen.
How can i do that?
Thank you
By default, a modal view controller is meant to take up the entire screen (on an iPhone/iPod, at least). Because of this, it covers whatever you have on screen at the time.
A view controller presented via modal segue is meant to live on its own. If you want to keep your Navigation and TabBar, then just use a push segue to present the new ViewController. Remember to use this kind of segue, your presenting controller needs to be part of a UINavigationController already.
Use this to push a ViewController. If it is a UINavigationController it will push its linked RootViewController by itsself.
Create a viewController to push: (Using Storyboard)
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
or (Using Code/Nibs)
LoginViewController *viewController = [[LoginViewController alloc] init]; //initWithNibNamed in case you are using nibs.
//in case you want to start a new Navigation: UINavigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
and push with:
[self.navigationController pushViewController:vc animated:true];
Also, if you are using Storyboards for the segues you can use this to do all the stuff. Remember to set the segue identifier.
[self performSegueWithIdentifier:#"pushLoginViewController" sender:self]; //Segue needs to exist and to be linked with the performing controller. Only use this if you need to trigger the segue with coder rather than an interface object.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"pushLiftDetail"]) {
[[segue.destinationViewController someMethod:]];
segue.destinationViewController.someProperty = x;
}
}
I think you'll need to add a UITabBar to the modal view and implement/duplicate the buttons and functionality that your main bar has. The essence of a modal window is it has total control until it is dismissed.
You might try putting your UITabBarController into a NavBarController, but I'm not certain that this will work.
UITabBarController -> NavBarController -> Modal View

UIViewController to know if it got pushed or popped?

I have a main UITableView, when cell is pressed it goes to another UITableView and when a cell is pressed there it goes to a DetailView of that cell.
I want the middle UITableView to behave differently depending on if the detailView got popped or the UITableView itself got pushed. If the view got pushed on from the main table I want to scroll to the top, if it is shown after a DetailView got popped I want it to stay at the same position.
Any suggestions?
you could call a scrollToTop method on the DetailViewController after you have pushed it to the navigationController.
Something like that:
if (!detailViewController) {
detailViewController = [[DetailViewController alloc] initWithNibName:nil bundle:nil];
}
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController scrollToTop];
// or use the tableView directly:
// [detailViewController.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
In your Middle View Controller, examine which view is next-to-display directly from the UINavigationController stack:
- (void)viewWillDisappear:(BOOL)animated
{
if ([self.navigationController.topViewController isEqual:(UITableViewController *)tvcDetailView]) {
// Detail view has been pushed onto the UINavigationController stack
}
else {
// Middle view has been popped from the UINavigationController stack
}
}
Create a BOOL #property on your middle UIViewController property called wasPushed or something similar, and when you initialise it from UIViewController 1, set the property on the new instance, push it onto the nav stack and you can then use your property in your middle view controller's loadView, viewDidLoad, viewWill/DidAppear methods.
As soon as you've used it, set it back to FALSE or NO (or whatever) and when you end up coming back to it due to popping off your 3rd view controller you'll have it as FALSE/NO in your loadView, viewDidLoad etc.. methods.