dace
dace

Reputation: 6373

How to have an action in one view controller start another in a different view controller?

New to iOS development & Objective-C and am a little unsure how to go about solving this issue.

I'm working on a project that works like a video player. There are two ViewControllers:

In the MenuViewController, I want to be able to click onto a button (video title) :

- (IBAction)videoOne:(id)sender
{
    PlayerViewController * vc = [[PlayerViewController alloc] initWithNibName:@"PlayerViewController" bundle:nil];

    [self presentModalViewController:vc animated:YES];
}

and have an action that's currently defined in the PlayerViewController automatically execute as soon as its loaded.

Is there a way to have a button in one ViewController call the action in another ViewController as soon as that second ViewController has loaded?

Thanks!

Upvotes: 0

Views: 935

Answers (3)

Vinod Vishwanath
Vinod Vishwanath

Reputation: 5911

The right way to solve this problem will be set up a delegate pattern between the two view-controllers.

Example:

@protocol PlayerViewControllerDelegate<NSObject>
{
    -(void)playerViewControllerViewDidLoad:(PlayerViewController *)playerVC;
}

Then, in PlayerViewController.h create a weak delegate variable:

@property (nonatomic, weak) id<PlayerViewControllerDelegate> delegate;

In PlayerViewController.m, notify the delegate on viewDidLoad:

-(void)viewDidLoad {

    [super viewDidLoad];

    [self.delegate playerViewControllerViewDidLoad:self]

}

In MenuViewController:

- (IBAction)videoOne:(id)sender
{
    PlayerViewController * vc = [[PlayerViewController alloc] initWithNibName:@"PlayerViewController" bundle:nil];
    vc.delegate = self
    [self presentViewController:vc animated:YES];
}

Finally, implement the protocol in MenuViewController, and you're ready to go:

@interface MenuViewController : UIViewController<PlayerViewControllerDelegate>

@end

@implementation MenuViewController

-(void)playerViewControllerViewDidLoad:(PlayerViewController*)playerVC
{
    [playerVC playVideo];
}

@end

Upvotes: 2

Tom Leu
Tom Leu

Reputation: 142

It is usually not good practice to have one controller controlling the behavior of another. Instead, you can have the MenuViewController create the PlayerViewController and set variables so the new player knows how to behave based on its internal state.

There are several UIViewController methods that you can override in order to perform actions during the controller's lifecycle. Based on your question it seems like you want the viewDidLoad method.

I am not sure how you are passing videos between controllers, but if you were using URLs (to Youtube videos for example) then you could do something like the following:

// MenuViewController.m
- (IBAction)videoOne:(id)sender {

    PlayerViewController* vc = [[PlayerViewController alloc] initWithNibName:@"PlayerViewController" bundle:nil];

    // Pass any necessary data to the controller before displaying it
    vc.videoURL = [self getURLForSender:sender];

    [self presentViewController:vc animated:YES completion:nil];
}

// PlayerViewController.m
- (void)viewDidAppear {
    // View did appear will only be called after the controller has displayed
    // its primary view as well as any views defined in your storyboard or 
    // xib. You can safely assume that your views are visible at this point.

    [super viewDidAppear];

    if (self.videoURL) {
        [self playVideo];
    }
}

You would need to define the property videoURL on PlayerViewController and expose it publicly. If you are using local files (such as from the user's photo storage) you could pass the video to the new view controller before presenting it.

There are other UIViewController lifecycle methods that you can override. They are explained in more depth in this post as well as Apple's UIViewController Documentation.

Edit: changed presentModalViewController:animated: to presentViewController:animated:completion: and changed viewDidLoad to viewDidAppear as it seems more appropriate for the question.

Upvotes: 2

jscs
jscs

Reputation: 64022

presentModalViewController:animated: is deprecated. Use presentViewController:animated:completion: instead.

In the completion Block, you can call a method on the presented view controller:

[self presentViewController:otherVC
                   animated:YES
                 completion:^{ [otherVC startPlaying]; }];

The completion is run after the presented controller's viewDidAppear.

Upvotes: 1

Related Questions