将信息从 UINavigationController 传递到嵌入式 UIViewController

Posted

技术标签:

【中文标题】将信息从 UINavigationController 传递到嵌入式 UIViewController【英文标题】:Passing info from UINavigationController to embedded UIViewController 【发布时间】:2014-01-29 20:51:40 【问题描述】:

概要

由于我没有让我的应用按我的意图传递数据,我被引导提出以下问题:

一般来说,如何将数据从导航控制器传递到其 嵌入式视图控制器? 具体来说,prepareForSegue 导航控制器中的方法曾经被调用过吗?如果有,怎么做?

设置

我有以下几点:

一个视图,标题为用户视图控制器,链接到自定义类JRMUserViewController(扩展UIViewController)。此视图嵌入: 导航视图,标题为导航到用户视图,链接到自定义类JRMNavigationToUserViewController(扩展UINavigationController)。重要提示:首先,我没有在导航控制器中嵌入用户视图控制器。导航控制器及其链接类不存在。 A Table View 标题为Issue Table View Controller,链接到自定义类JRMIssuesTableViewController(扩展UITableViewController)。 一个按钮链接到模态转场,该转场转至导航到用户视图。转场由文本“@987654332”标识@"。

预期功能

这个想法是,当我在问题表视图控制器上时,我可以点击按钮,它会带我到用户视图控制器,在那里我将看到当前用户的头像,以及带有当前用户全名的标签。

为了实现这一点(在我将 User View Controller 嵌入导航控制器之前),我在前者的 prepareForSegue 方法中将数据从 JRMIssuesTableViewController 传递到 JRMUserViewController

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
    NSLog(@"\nSEGUE IDENTIFIER:\n%@", [segue identifier]);
    if([[segue identifier] isEqualToString:@"IssuesToUserView"]) 
        JRMUserViewController *vc = [segue destinationViewController];
        vc.currentUser = self.currentUser;
        NSURL *url = [[NSURL alloc] initWithString:[vc.currentUser.avatarUrls objectForKey:@"48x48"]];
        NSLog(@"\nURL:\n%@", url);
        NSData *data = [NSData dataWithContentsOfURL:url];
        [vc.view addSubview:vc.avatar];
        [vc.avatar setImage:[[UIImage alloc] initWithData:data]];
        vc.userLabel.text = vc.currentUser.displayName;    
   

它成功了。单击第一个视图上的按钮将我带到第二个视图,其中显示了当前用户的信息:

意外行为

此后,出于必要,我不得不将用户视图控制器嵌入到我之前提到的导航控制器中。当然,在这样做之后,我在运行时遇到了未捕获的异常,因为在我重写的 prepareForSegue 中,我将消息发送到导航控制器而不是用户视图控制器。为了解决这个问题,我扩展了UINavigationController,将其命名为JRMNavigationToUserViewController,并将导航视图链接到它,正如我在设置中提到的那样。

然后,考虑到 UINavigationController 在进入其嵌入式视图之前会调用自己的 prepareForSegue,我覆盖了 JRMNavigationToUserViewController 中的 prepareForSegue 方法:

- (id)passValuesToDesitinationOfSegue:(UIStoryboardSegue *)segue 
    NSLog(@"Calling [JRMNavigationToUserViewController passValuesToDestinationOfSegue]");
    JRMUserViewController *destination = [segue destinationViewController];
    destination.server = self.server;
    destination.currentUser = self.currentUser;
    destination.avatar = self.avatar;
    [destination.view addSubview:destination.avatar];
    destination.userLabel = self.userLabel;
    return destination;


#pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 
    NSLog(@"Calling [JRMNavigationToUserViewController prepareForSegue]");
    [self passValuesToDesitinationOfSegue:segue];

这一次,当我点击按钮时,用户视图控制器没有收到数据。它看起来像这样:

显然,JRMNavigationToUserViewController 中的 prepareForSegue 方法从未被调用,因为它会记录消息:

Calling [JRMNavigationToUserViewController prepareForSegue]
Calling [JRMNavigationToUserViewController passValuesToDestinationOfSegue]

我在控制台的任何地方都找不到这些行。

总结

这是我的问题:

一般来说,如何将数据从导航控制器传递到其 嵌入式视图控制器? 具体来说,prepareForSegue 导航控制器中的方法曾经被调用过吗?如果有,怎么做?

【问题讨论】:

导航控制器通常没有自己的内容——它们希望管理其他视图控制器的堆栈,并显示当前位于堆栈顶部的控制器视图。如果您将UINavigationController 子类化为显示自己的内容,那么您肯定会让自己的生活变得比需要的更加困难。你能说明你决定继承UINavigationController的原因吗? 我对它进行了子类化,因此我可以覆盖 prepareForSegue 以尝试将数据传递到嵌入视图。然而,我怀疑这表明我对 UINavigationController 的工作原理有多少误解。这就是我问这个问题的原因。 【参考方案1】:

你在这里误用了UINavigationController。看看你的故事板:你有一个表格控制器,它以某种方式呈现一个导航控制器,而导航控制器又具有一个用户控制器作为它的根控制器。我认为您想要的是让导航控制器包含表格控制器,并在表格上点击触发对用户视图控制器的推送。因此,导航控制器应该在左侧,表格控制器在中间,用户控制器在右侧。

然后,表格控制器中的-prepareForSegue:sender: 方法将被写入,使其查看选定的单元格并设置用户控制器的相应属性(这是segue 的目的地)。

【讨论】:

你是对的。我摆脱了导航控制器,它工作了(问题视图上游已经有一个导航控制器)。您的回答帮助我更好地理解UINavigationController。谢谢!

以上是关于将信息从 UINavigationController 传递到嵌入式 UIViewController的主要内容,如果未能解决你的问题,请参考以下文章

从模态视图或推送视图调用父方法到presentingViewController

UINavigationController 风格

如何将标签栏内的视图旋转为纵向

UINavigationController & SplitViewController

UINavigationController

全屏显示 ViewController