Communication between controllers iOS - objective-c

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]

Related

transition between two view with CATransition

I ran into a transition problem today. It's hard to explain to I recorded a very short clip.
I want the first transition (when I click on the + button) to look exactly like the second one (when I click on
Here's the clip:
transition clip
this is my code :
My Source Code
How are you doing it now then? You didn't give a lot of info but you're using a navigation controller right? Do you need to? One option is to present the second screen from the first. In that case you handle the transitions yourself and you could even give the two view controllers a common base class if several components (like the + sign) are common to both. I have some code I can post if that might be useful...
To present and dismiss a vc:
Have a second view controller as a property in your root view controller:
#property (nonatomic, strong) UIViewController *secondViewController;
in the button pressed method for your plus button:
[self presentViewController:_secondViewController animated:YES completion:nil];
in your presented view controller, in the button pressed method for your back button:
[self dismissViewControllerAnimated:YES completion:^{
}];
Also, if you want to slide horizontally as in this case you'll need to do some custom animation, by creating an animator object that is a UIVIewControllerAnimatedTransitioning delegate. I recommend you read up on that - I also have some examples of that for you if you wish.
Cheers.

Object becomes Nil when pushing controller

I have a the first application controller, MAViewControllerMenu, and when that controller loads, I already allocate the next controller, imageControllerView.
- (void)viewDidAppear{
[super viewDidAppear:(YES)];
if (!imageControllerView)
imageControllerView = [[self storyboard] instantiateViewControllerWithIdentifier:#"chosenImageController"];
}
Then, I select an image from the image picker, and want to move to the next controller,imageControllerView, where the image would be displayed. I set the next window's image property as follows:
imageControllerView.image = [[self.pageViews objectAtIndex:(centered_image_ind)] image];
This line works, I checked that there's a value in imageControllerView.image.
However, when I move to the next controller,imageControllerView , I notice that the memory address of imageControllerView changes, or in other words, imageControllerView's properties that I change before moving to that controller, specifically image, reset when I move there.
Instead of throwing code here, I was hoping you could let me know what I should provide.
I think it's a common problem people know of:
Controller's objects re-init'ing when moving from one controller to another.
Here's a screen shot that might give a hint of what Im trying to do
Left most one is where I select pictures which in turn go into the slide show scrollview. Then I click next, and the image is supposed to appear in the centered ImageView
Thanks
OK...
You cannot "already allocate the next view controller" this won't work. There is no point in creating it like this at all. You can delete the imageViewController property (or iVar) completely.
The arrows that you have between the view controllers in your storyboard are segues. In Interface Builder you can select a segue and give it an identifier. For instance you would use something like #"ImageViewSegue".
I guess the segue is attached to the Next button. This is fine.
Now, in your MAViewControllerMenu you need to put this method...
- (void)prepareForSegue:(UIStoryBoardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ImageViewSegue"]) {
// the controller is CREATED by the segue.
// the one you create in view did load is never used
ImageViewController *controller = segue.destinationController;
controller.image = [[self.pageViews objectAtIndex:(centered_image_ind)] image];
}
}
Now for the segues in the other direction...
You appear to be using segues to dismiss the modal views. You can't do this. What it will do is create a new view controller and present that instead of dismissing the presented view.
i.e. you'll go...
A -> B -> C -> B -> A -> B
// you'll now have 6 view controllers in memory
// each segue will create a fresh view controller with no values set.
What you want is...
A -> B -> C
A -> B
A
// now you only have one view controller because the others were dismissed.
// when you dismiss a view controller it will go back to the original one.
// the original one will have all the values you set previously.
To do this you need to create a method something like...
- (IBAction)dismissView
{
[self dismissViewControllerAnimated:YES completion:nil];
}
Then whatever the button is for your dismiss action attach it to this method.
Now delete all the backwards curly segues.
Passing info back
To pass info back to the original view controller you need a delegation pattern or something similar.
You can read more about creating a delegate at This random Google Search
Create a delegate method something like...
- (void)imageViewSelectedImage:(UIImage *)image;
or something like this.
Now when you do prepareForSegue you can do...
controller.delegate = self;
and have a method...
- (void)imageViewSelectedImage:(UIImage *)image
{
// save the method that has been sent back into an array or something
}
I might be wrong, but seems you go to your second view controller using a segue, it is normal your controller instance isn't the same than the one retrieved by [[self storyboard] instantiateViewControllerWithIdentifier:#"chosenImageController"]
you should take a look at - (void) prepareForSegue:(UIStoryboardSegue *)segue
(UIViewController method)
inside this method set your image property to the segue destination controller (check the identifier of the segue)

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.

Passing NSIndexPath to New View

I am having real troubles passing an NSIndexPath to my new view. This is how the app works:
I have a UIBarButtonItem in my nab br, tap that and you get a popover view, this shows a bunch of stuff. I need to get an NSIndexPath from my main view, to this popover view.
I have a property for the NSIndexPath in my popover view class and the popover transition is connected up in my storyboard.
Then I have this code to pass the index path across views:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"statsPopover"])
{
StatsViewController *statsVC = [segue destinationViewController];
statsVC.selectedIndex = stageSelectionTable.indexPathForSelectedRow;
}
}
However, while this gets called, the index path isn't actually sent between views. My index path on the popover is always the default, 0,0 row and section.
You say you know from debugging/logging that the method is running, your if statement is triggered, and stageSelectionTable.indexPathForSelectedRow has the value you expect.
Doing that kind of diagnosis puts you on the right path to solving your issue. Keep at it -- if you test some other things with NSLog or the debugger you should be able to find the problem.
Do you know that statsVC is non-nil? If it's nil, your message to set selectedIndex does nothing.
Is statsVC the class you expect? If, say, the (table?) view in your popover is embedded in a navigation controller, segue.destinationViewController will point to the nav controller, and you'll need to look into its child view controllers array to find the one you're looking for.
Is whatever accessor method your StatsViewController class is using for its selectedIndex property working right? (This shouldn't be a problem if it's a synthesized accessor for a strong/retain property.)
In your StatsViewController class, are you trying to work with selectedIndex before it actually gets set? Setting a property in prepareForSegue:sender: and then using it in viewDidLoad should work fine, but using it in awakeFromNib might not, and using it in an init... method definitely won't.

Calling a method in another viewController

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