子视图控制器如何使用父视图控制器中定义的方法

3
我有这样一种情况,子视图控制器试图显示多个视图控制器,而在执行此操作时,子视图控制器需要访问父视图控制器中的播放暂停操作方法。如何实现子视图控制器使用定义在父视图控制器中的播放暂停操作方法,即暂停音频播放器、暂停计时器和暂停图层:self.view.layer?
我会非常感谢任何帮助解决这个问题的帮助。
谢谢
4个回答

9
您可以使用parentViewController属性访问视图控制器的父级。
if([self.parentViewController isKindOfClass:[SomeViewController class]]) {
    SomeViewController* viewController = (SomeViewController*)self.parentViewController;

    [viewController foo];
}

然而,这取决于您的视图控制器之间的关系。根据您的问题,我推断您有多个子项的父子关系,如果我错了,请纠正我!这与模态视图控制器呈现非常不同,其中仅呈现一个视图控制器,并且它要求用户立即注意。
解释:
似乎存在一些混淆,关于UIViewController上的parentViewController和presentingViewController属性之间的区别。有两种不同的视图控制器关系,每种关系都适用于这些属性中的一种。
如果您希望将多个视图控制器的视图添加为父视图控制器的子视图,则使用view controller containment。在这种情况下,任何添加为父视图控制器的子视图(子项)的视图在访问parentViewController属性时将返回父视图控制器(控制子项的superview;父视图)。在这种情况下,presentingViewController属性返回null。
例如,在父视图控制器中:
- (void)viewDidLoad {
    [super viewDidLoad];

    SomeViewController* someVC = [[SomeViewController alloc] init];

    [self addChildViewController:someVC];
    [self.view addSubview:someVC.view];
    [someVC.view setFrame:<SOME_FRAME>];
    [someVC didMoveToParentViewController:self];

    AnotherViewController* anotherVC = [[AnotherViewController alloc] init];

    [self addChildViewController:anotherVC];
    [self.view addSubview:anotherVC.view];
    [anotherVC.view setFrame:<ANOTHER_FRAME>];
    [anotherVC didMoveToParentViewController:self];

    /* this prints self */
    NSLog(@"%@", someVC.parentViewController);

    /* this prints null */
    NSLog(@"%@", someVC.presentingViewController);


    /* this prints self */
    NSLog(@"%@", anotherVC.parentViewController);

    /* this prints null */
    NSLog(@"%@", anotherVC.presentingViewController);
}

相反的,如果您只想展示一个模态视图控制器(这种情况比上述一对多的父子关系更为常见),那么使用 presentingViewController 属性。
例如,在呈现视图控制器中:
- (void)someActionTriggered {
    SomeViewController* viewController = [[SomeViewController alloc] init];
    
    [self presentViewController:viewController animated:YES completion:nil];

    /* this prints null */
    NSLog(@"%@", viewController.parentViewController);

    /* this prints self, or a tab bar controller if 'self' is contained in one */
    NSLog(@"%@", viewController.presentingViewController);
}

虽然由于模态视图控制器在iOS中的普及,presentingViewController可能更常见,但视图控制器之间的父子关系是完全合法的,parentViewControllerchildViewController属性在iOS 5中并未被弃用,它们的使用方式只是发生了变化。您可以从文档中阅读以下摘录:

讨论

如果接收者是容器视图控制器的子级,则此属性保存其所包含的视图控制器。如果接收者没有父级,则此属性中的值为nil。

在iOS 5.0之前,如果一个视图没有父视图控制器并且正在被呈现,则会返回呈现视图控制器。在iOS 5上,不再出现此行为。取而代之的是,使用presentingViewController属性来访问呈现视图控制器。


Jack 指出 parentViewController 已被弃用。 - nielsbot
parentViewController 没有被弃用。在 iOS 5 中,它的使用方式发生了变化,但它仍然具有特定的目的。您可以查看 Stack Overflow 上关于视图控制器包含的先前问题(其中使用了 parentViewController 属性,而不是 presentingViewController),这似乎是 OP 所询问的内容,链接如下:https://dev59.com/9msy5IYBdhLWcg3wsQFj - eric.mitchell
1
@Rickay 对不起,是我看错了!我会取消你的踩,并给你的回答点个赞以表歉意。 - Jack Humphries

1
ParentViewController.h文件中。
-(void)PlayMusic;

ParentViewController.m中。
-(IBAction)PlayMusic:(id)sender {
       [self playMusic];
}

在子视图控制器的播放按钮的IBAction中执行以下操作:
-(IBAction)PlayMusic:(id)sender {
       ParentViewController *parent=self.parentViewController;
       [parent playMusic];
}

1
每个视图控制器都有一个属性叫做presentingViewController(如果ViewController1以模态方式呈现ViewController2,那么ViewController1就是ViewController2的presentingViewController)。

ViewController *viewController = (ViewController *)self.presentingViewController;
[viewController function];

另一个选项是使用NSNotificationCenter。这样,您可以轻松地从应用程序的任何位置调用父视图控制器的方法。

ParentViewController.m

-(void)viewDidLoad {

    ...

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(method) name:@"Toggle Play" object:nil];

}

ChildViewController.m

[[NSNotificationCenter defaultCenter] postNotificationName:@"Toggle Play" object:nil];

@nielsbot,你能澄清一下问题吗? - Jack Humphries
没问题——我正在提供另一种选择。您可以将响应者链想象成另一种委托方法调用的方式,在这种情况下,委托是响应者链上的一个对象(您不需要关心哪个)。这不需要了解您所包含的视图/视图控制器,并且不需要预先安排(添加通知观察器)。 - nielsbot
此外,我注意到 UIResponder 缺少了 NSResponder-tryToPerform:with: 方法... 但这可以通过添加一个类别轻松解决。 - nielsbot
Jack,你是错误的。parentViewController在iOS 5中并未被弃用。父子关系和呈现-被呈现关系是两种完全不同的视图控制器关系。当一个或多个视图控制器作为子控制器添加到一个父控制器中时,使用父子关系。当一个视图控制器以模态方式呈现单个视图控制器时,就会产生呈现-被呈现关系。文档:http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html - eric.mitchell
请查看我回答的编辑,那里有更详细的解释。这里只能输入600个字符! - eric.mitchell

0

您可以使用以下方法从子视图访问父视图,即使父视图是UINavigationControllerUIViewController

self.parentViewController

你可以像这样向上移动

self.parentViewController!.parentViewController as! PARENT_VIEW_CONTROLLER

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接