Calling a method in another viewController - objective-c

I have a UINavigationController containing a UIViewController with an MKMapView onto which I push a UITableViewController which contains a list of items obtained from Core Data. Based on the selected item on the table, I want to return to the navigation controller and call a method, passing the object selected in the table. How can I achieve this?

You don't actually "return" to a UINavigationController. That is to say, it has no UIView associated with it. It is intended to be treated as a way to just keep track of a stack of UIViewControllers. Since it sounds like this UITableViewController is your root view, there isn't anywhere to "return" back to. I suggest you simply push another UIViewController in the selectRow: handler that will be able to bring up the view detailing the selected text field.

You can make your first UIViewController a delegate of your UITableViewController, and invoke appropriate methods when an object is selected in the table. Something like this:
if (delegate && [delegate respondsToSelector:#selector(tableView:didSelectObject:)]) {
[delegate tableView:self didSelectObject:object];
}

Related

Return for a push segue

I am new to story boards and I am trying to move between table view controllers.
I understand how to set up a segue and how to send data to the new story board but my question is returning data back. If I use the push style segue it gives me an automatic back button. I want a page that will create a "job" and save it if they hit save (a bar button I created on the other side of the title) When I set up the segue to go back to the main page from the save button it made that main table view controller a child (instead of simply going back to it's original state). The work around I was thinking was saving it to a file when they hit save and whenever they load the main table view it loads from that file. Is this a common and correct way to do this or should I be trying to return that object and save it in the main table view controller?
A common approach is to use delegation. Since ViewControllers should be as independent as it is possible, we have to minimize dependencies between them. And actually your idea with the file, if I understand it correctly, does it as well. But using files to organize a communication between ViewControllers is not very convinient.
Usually you declare a #protocol SecondViewControllerDelegate for your second ViewController (where you click a "Save" button). With methods like:
#protocol YourSecondViewControllerDelegate <NSObject>
-(void)yourSecondViewControllerDidCancel:(YourSecondViewController*)controller; //if you have a cancel button
-(void)yourSecondViewControllerDidFinish:(YourSecondViewController*)controller yourDataToReturn:(SomeData*)data andSomeMoreData:(AnotherDataType*)data2;
#end
Then you add a property like this to your SecondViewController:
#property (nonatomic, assign) id<YourSecondViewControllerDelegate> delegate; //Do not retain it!
Then you adopt your protocol in your MainViewController.
#interface MainViewController()<YourSecondViewControllerDelegate> //you can do it in the private category to keep the class interface clear.
#end
#implementation
//don't forget to implement those methods here :)
#end
And when you trigger your segue from the MainViewController, you can set your MainViewController as a delegate for the SecondViewController:
SecondViewController *destinationController = [[SecondViewController alloc] init]; //Just for example.
destinationController.delegate = self;
//trigger a segue :)
When the user presses the Save button in the SecondViewController, you call the delegate's yourSecondViewControllerDidFinish:
[self.delegate yourSecondViewControllerDidFinish: self yourDataToReturn: someData andSomeMoreDate: someMoreData];
This way MainController's yourSecondViewControllerDidFinish method will be called. And you can pick someData and someMoreData up there.
You can get more details about it in this tutorial:
Apple's your second iOS app tutorial
If you're making a segue to go "back" to a controller, then that segue needs to be an unwind segue. An unwind segue goes back to the same instance of the controller that you came from originally. If you need to send data back to that controller, you can do it in prepareForSegue.

Communication between controllers iOS

first of all I want to show you my storyboard:
I have a Label in the CUVCViewController (the first view of the left) and a UISlider in the CUVCViewControllerPageTwo (the second view). When I tap on the "page 2" button I can change the value of the UISlider.
I want to show the value of the UISlider in the label, but I don't understand how I can do it!
I have tried with delegation, but I don't understand how I can implement it!
Can someone help me? Thanks!!
Ok, so this one is pretty easy, but I'm really not sure how far you've got! I'm going to assume that you just want to know how to pass the data from the UISlider back to the first view controller.
In the class of the first view controller, you need to implement the method
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
This is called just before the segue to the second view controller. you can then set your first view controller as a delegate to the second. So you would need to set up a #property on the second view controller of type 'first view controller' and call it, say, delegate (you could give it any name)
In your -prepareForSegue: method, do this
SecondViewController *secondController = segue.destinationViewController;
secondController.delegate = self;
Then from this point you can refer to your first view controller as delegate from your second. Prehaps you could pass the data back from the UISlider via a method call on the first, or by setting a property on the first
eg [delegate sliderDidUpdate:sliderValue]

Push view to navigation controller from button in other class

I have a UIButton that I create in my sub class ViewController, and add it to my MainViewController.
Now, I added a target method to this button that should push another view controller to my Navigation controller (the one that in the MainViewController).
I know that the method did call when I push the button, but the view wasn't push to the Navigation Controller.
I scanned this drawing - this is the drawing (I also added part of my code):
This is the code I'm using in my button:
(remember it's in a deferent ViewController).
- (void)buttonPressed:(UIButton *)sender
{
Photo_ScreenGlobalView *photo = [[Photo_ScreenGlobalView alloc] init];
[self.navigationController pushViewController:photo animated:YES];
}
Usually I solve these situations with delegation. If there is a view controller which is subordinate to another (i.e. a "sub" view controller) but should have the ability to trigger navigation changes, etc... then it should have a weak pointer back to it's 'parent'. Then the parent VC should implement an appropriately named protocol with a callback for the child to use. The names of these things can be generic, such as #property navigationDelegate and requestNavigationToViewController: or they can be more semantic, such as #property userFormDelegate and userFormDoneButtonPressed:
Generally speaking, a subordinate view controller should not be able to directly modify navigation at it's parent's level; but it can trigger it via more loosely-coupoled interfaces like these.
i came back to let you all know how i actually did it.
after googling a lot found this nice and quick guide how to make DELEGATE
and working with delegate solved all my problems. if you need any help don't hesitate to send me PM.
this is the guide:
http://css.dzone.com/articles/do-not-publishcreating-your

Dismissing the split view popover controller

I have a UISplitViewController with the master view set up like this:
UITabBarController
Tab1:
UINavigationController -> UIViewController -> UIViewController
Tab2:
UINavigationController -> UIViewController
Each of the UIViewControllers is a table view, and when the user chooses a row in the last one, an image is shown in the detail view, which contains a UIScrollView.
The tab bar Controller is the UISplitViewControllerDelegate and handles putting up the button on a toolbar at the top of the scroll view.
The problem is, I want to add code to dismiss the popover when the user makes their choice. The pointer to the popover has to be saved in the tab bar controller when the button goes up, and then used to dismiss the popover several view controllers down the line when the user makes their final selection. There doesn't seem to be any way for the view controller that needs that pointer to get at it, without doing something gross like storing it in the App Delegate.
I don't see other people asking this question, which leads me to believe that I've once again overlooked something simple. Please enlighten me!
It sounds like your tab bar controller is already a subclass of UITabBarController, which means that you've already got some custom code in there. I would suggest that the tab bar controller is the primary owner of the popover, and it is the table view controller's responsibility to simply notify the tab bar controller that a selection has been made. The tab bar controller can respond to that message by dismissing the popover. You can take advantage of the fact that UIViewController already has a method for accessing the tab bar controller that contains a given controller.
So it would look something like this:
#interface MyTabBarController : UITabBarController
- (void)itemWasSelected;
#end
#implementation MyTabBarController {
UIPopoverController *popover;
}
- (void)itemWasSelected {
[popover dismissPopoverControllerAnimated:YES];
}
#end
//////////////
#implementation TableController
- (void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)path {
// Do whatever else you want to do
MyTabBarController *tabController = (MyTabBarController *)self.tabBarController;
[tabController itemWasSelected];
}
With this solution, the table controller doesn't have to know anything about the popover; it just has to know that it's going to be presented inside a MyTabBarController, which seems a reasonable thing for it to know.
You could create a singleton class to track your popover status and then make it available to all classes equally and easily. That way it could easily be updated and accessed from any code without having to go straight to overburdening the app delegate even though thats basically the same idea but a bit cleaner in its own singleton.

iOS Dev, How can I call a method in the super class of my UIViewController?

i have two UIViewControllers for example A and B.
On A there is a button when pushed loads view B as a sub view. Using the standard initWithNibName. On B there is a button which dismisses View B and should call a method in view A (its Parent View). I thought it should be a simple [super methoddName:perimeter] but this doesn't work. after placing a NSLog printing out the name of the parentViewController it returned null which is odd as surly it should return View A as the Parent view.
any Ideas Cheers
super refers to your class's superclass, not its parent view controller.
A way to quickly do this is create a new init method that takes an instance of view controller A, use that to set the target of your button.
The best way is to define a new protocol on view controller B. Make view controller A conform to it. On init of B, pass in a refernce to A to use as your delegate. Then on the button push in B call the desired method on the delegate.
You might be better off by letting view controller A be a delegate on view controller B.
A can set the delegate property on B when after loading it but before pushing it into view, and when B needs to call the required method, it can just call it on the delegate object.
That makes the coupling between the controllers looser, and if you let the delegate conform to a protocol, you can keep B's knowledge of A to a minimum.
It's better design, if you ask me.
parentViewController won't work if you add view controller B's view as a subview. You will have to find the view controller A in a different way.
Say, if you had added B's view as a subview like this,
[A.view addSubview:B.view];
then you can call view controller A like this.
[[B.view.superview nextResponder] methoddName:perimeter];
If you have added B.view as a subview somewhere within the view hierarchy of A.view.
UIResponder * responder = B.view.superview;
do {
responder = [responder nextResponder];
} while ( ![responder isMemberOfClass:[A class]] );
// `responder` is referencing your view controller A. You will have to cast it.
Easiest way to do this especially if it is a static method:
ViewControllerB
#import "ViewControllerA.h"
- (void)dismissView{
//implementation to close the view
[ViewControllerA methodName:perimeter];
}
Good Luck!