Vlad Z
Vlad Z

Reputation: 385

Communication between UIViewControllers

I am new with Objective-C so apologies for a dumb question.

I am opening an "options" view controller from my main view controller. Both are built in the storyboard. Before and after presenting the options controller I need to stop and start a timer on my main view controller. After the options controller is closed (a button calls dismiss) I need to send some info back to my main controller or at least let my main controller know that it needs to refresh some values.

MAIN QUESTION What's the best way of presenting a view controller and executing some presenter's methods before and after opening?

WHAT I'VE TRIED I found a few ways to do it, but they are all cumbersome and I assume that there must be some plausible way of doing it.

  1. Ideally I'd like to use the segue I set up in the storyboard between the two controllers.
  2. I managed to call the options controller programmatically by accessing the storyboard and calling instantiateViewControllerWithIdentifier. It worked but looks a bit complex.
  3. I was not able to find a delegate method on the UIViewController to handle the dismiss event
  4. When I was trying to access the main controller in the options controller via presentingViewController and downcasting it, I got a linkage error by including my .h file twice (not sure what are the Obj-C standards of using #define).

Appreciate your help...

Upvotes: 4

Views: 768

Answers (5)

Vlad Z
Vlad Z

Reputation: 385

Thanks for replies.

I ended up with

  1. Calling prepareForSegue to execute pre-transition code

  2. Calling performSelector on presentingViewController when releasing presented view controller.

I am sure other suggestions would work too.

Upvotes: 0

Michael Mangold
Michael Mangold

Reputation: 1801

MAIN QUESTION What's the best way of presenting a view controller and executing some presenter's methods before and after opening?

Just in case the answers above are a bit more involved than you'd like, I'll suggest that the easiest way to execute a presenter's methods before opening is to do so in the presenter's prepareForSegue method. If you need to send data to the destination view controller, you can access its properties this way:

ViewController *destinationVC = [segue destinationViewController];

An easy way to execute the presenter's methods after opening would be:

ViewControllerSubclass *previousVC = [self presentingViewController];

And then use the class or instance to execute your class or instance methods. You could do this in the destination's viewWillAppear.

Sorry if you already knew all this; it's often difficult to surmise what level of complexity is needed.

Upvotes: 2

Ahab
Ahab

Reputation: 311

All of this can be done quite easily with storyboard and NSNotificationCenter, and NSCoding. In the viewDidLoad method of your main controller, put this code:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(receiveNotification:) 
                                             name:@"Update"
                                           object:nil];

Then create this method in the same controller:

(void)receiveNotification:(NSNotification*)notification
{
   //...
}

When you want to make the main controller update from the options controller:

[[NSNotificationCenter defaultCenter] postNotificationName:@"Update" object:self];

Also, I would suggest using NSArchiving for Basic Data Persistence. Just found this tutorial, looks pretty good. http://samsoff.es/posts/archiving-objective-c-objects-with-nscoding

Basically, create an object that can store information, code it using nscoding, and then uncode it whenever you need it. It has worked great for me.

Hope that helps!

Upvotes: 2

trumpetlicks
trumpetlicks

Reputation: 7065

I have run into this with almost every app I have on the market. Difference is I have never decided to go down the storyboard path.

The way I have always been able to accomplish this is to provide accessor functions between the controllers. You get past the linker issue by defining the cross defined controller as simply a UIViewController type within your options view header, then including the main view controller' header only in the .m file. Now when you call a main view controller routine from your options view, you will have to cast it to the type of your main view controller!

You will also have to provide a routine in your options view that will allow you to set the variable that will hold a pointer to your main view controller to self.

Example for your optionsView

@interface optionsViewController : UIViewController{
    UIViewController * myReactiveMainViewController;
}

-(void)setMyReactiveMainViewController:(UIViewController *)controller;

No in the .m file for the optionsView

#import "myMainViewController.h"

-(void)setMyReactiveMainViewController:(UIViewController *)controller{
    myReactiveMainViewController = controller;
}

In any other call back to the main view controller you will have to do this:

-(void)returnToMain{
    [(myMainViewController *)myReactiveMainViewController someCall:variable];
}

This example would of course assume that your myMainViewController implements a method called "someCall" that take on input parameter.

Upvotes: 1

Wim Haanstra
Wim Haanstra

Reputation: 5998

For communication between ViewControllers that are weakly linked, you could use the NSNotificationCenter:

https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html

Here you can send a message to all ViewControllers listening, which need to process some changes (for example an option to change the font size).

It's really easy to implement and it keeps certain ViewControllers less dependent on each other.

Upvotes: 2

Related Questions