【问题标题】:How to have an action in one view controller start another in a different view controller?如何让一个视图控制器中的一个动作在另一个视图控制器中启动另一个?
【发布时间】:2016-01-07 18:59:18
【问题描述】:

iOS 开发和 Objective-C 的新手,有点不确定如何解决这个问题。

我正在开发一个类似于视频播放器的项目。有两个 ViewController:

  • MenuViewController(有一个充当按钮的标题列表)
  • PlayerViewController(查看视频播放位置)

在 MenuViewController 中,我希望能够点击一个按钮(视频标题):

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

    [self presentModalViewController:vc animated:YES];
}

并让当前在 PlayerViewController 中定义的动作在加载后立即自动执行。

有没有办法让一个 ViewController 中的按钮在第二个 ViewController 加载后立即调用另一个 ViewController 中的操作?

谢谢!

【问题讨论】:

  • 使用委托来实现您的需要。或者将值/标志传递给另一个视图控制器,当你加载该视图控制器时,检查该值并加载必要的方法。
  • 你可以尝试传递一个块。似乎 PlayerViewController 知道“何时”(完成加载),而 MenuViewController 知道“如何”(应该做什么)。因此,您可以将一个块(“如何”)从 MenuViewController 传递给 PlayerViewController,然后它会在适当的时间(“何时”)执行该块。

标签: ios objective-c


【解决方案1】:

解决这个问题的正确方法是在两个视图控制器之间建立一个委托模式。

例子:

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

然后,在 PlayerViewController.h 中创建一个弱委托变量:

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

在 PlayerViewController.m 中,在 viewDidLoad 上通知代理:

-(void)viewDidLoad {

    [super viewDidLoad];

    [self.delegate playerViewControllerViewDidLoad:self]

}

在 MenuViewController 中:

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

最后,在 MenuViewController 中实现协议,就可以开始了:

@interface MenuViewController : UIViewController<PlayerViewControllerDelegate>

@end

@implementation MenuViewController

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

@end

【讨论】:

    【解决方案2】:

    让一个控制器控制另一个控制器的行为通常不是一个好习惯。相反,您可以让MenuViewController 创建PlayerViewController 并设置变量,以便新玩家知道如何根据其内部状态进行操作。

    您可以覆盖多个UIViewController 方法,以便在控制器的生命周期内执行操作。根据您的问题,您似乎想要 viewDidLoad 方法。

    我不确定您是如何在控制器之间传递视频的,但如果您使用的是 URL(例如 Youtube 视频),那么您可以执行以下操作:

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

    您需要在 PlayerViewController 上定义属性 videoURL 并将其公开。如果您正在使用本地文件(例如来自用户的照片存储),您可以在呈现视频之前将视频传递给新的视图控制器。

    您可以覆盖其他 UIViewController 生命周期方法。 in this postApple's UIViewController Documentation 对它们进行了更深入的解释。

    编辑:将presentModalViewController:animated: 更改为presentViewController:animated:completion: 并将viewDidLoad 更改为viewDidAppear,因为它似乎更适合该问题。

    【讨论】:

    • @JoshCaswell 感谢您的注意,我编辑了答案
    【解决方案3】:

    presentModalViewController:animated: 已弃用。请改用presentViewController:animated:completion:

    在完成块中,您可以在呈现的视图控制器上调用方法:

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

    完成是在提供的控制器的viewDidAppear之后运行的。

    【讨论】:

    • 我不知道我可以在完成块中调用它。在这种情况下,这是代表的替代方案吗?
    • 它没有那么灵活,@Mr.T:你不能真正得到任何信息,因为块在视图出现后立即运行,但你可以做一些像这样简单的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多