在嵌入在两个独立容器控制器中的视图之间实现委托

Posted

技术标签:

【中文标题】在嵌入在两个独立容器控制器中的视图之间实现委托【英文标题】:Implementing delegation between views embedded in two separate container controllers 【发布时间】:2013-06-05 20:35:42 【问题描述】:

我的故事板的相关部分如下所示: 您可以看到自定义“容器控制器”视图包含两个容器视图,一个通过嵌入式 segue 链接到导航控制器,另一个通过嵌入式 segue 链接到自定义“主视图控制器”(实现表视图控制器)。 Navigation Controller 组件还与自定义的“Location Filter Controller”有关系。

我需要实现委托,以便当位置过滤器控制器中的 UISteppers 之一是 incr./decr. 时,主视图控制器中的表视图知道相应地更新它显示的数据。

我并非不习惯使用协议/委托,但是这种在 segues 中的视图之间进行对话的独特情况真的在欺骗我!在大多数情况下,我在以下示例中取得了成功:Passing Data between View Controllers。但是,在这种情况下,我无法直接链接实例化视图,正如他在“传回数据”步骤 6 中所指示的那样。

我曾考虑使用单个对象,这些视图中的每一个都可以从中获取/设置必要的数据,但这里的问题是表视图不一定知道何时更新其内容,尽管它可以使用数据/应该更新。

这是来自 ContainerController.m 的代码 sn-p,我在其中设置了嵌入的 segues 以运行:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    DataHold *data = [[DataHold alloc] init]; // <-- this actually is a singleton object

    if([segue.identifier isEqualToString:@"locationEmbedSegue"])
    

    
    else if([segue.identifier isEqualToString:@"tableEmbedSegue"])
    
        [[segue destinationViewController] setDelegate:data.detailTableViewController];
        // ^ This part actually sets up a delegate so that the table view (Master View Controller)
        // delegates to the detail view controller of the overarching split view controller
        // and tells it what to display when a row is pressed.
    

感谢您的帮助!

【问题讨论】:

您应该将故事板屏幕截图直接嵌入到您的问题中,以便于阅读和将来参考(最好不要依赖第三方托管服务)。 哈哈,是的。我很想这样做,但我的代表仍然很差,我总共需要 15 个代表货币来嵌入屏幕截图! 胡。忘了那个。对不起:D 没问题,哈哈。一旦我获得 15 次代表,我可能会回来并用嵌入图片替换我迄今为止提出的问题中的几个外部 img 链接。 您是否使用 GuillaumeA 的答案实现了委托协议?在我看来,委托分配仍然是倒退的,但也许我误解了你想要的东西。由于更改是由 LocationFilterController 中的步进器进行的,因此它需要调用委托方法,而表视图控制器(而不是表视图)需要实现委托方法——这使得表视图controller 细节控制器的委托,而不是相反。 【参考方案1】:

我认为您将表格视图委托设置为您的位置过滤器控制器是正确的。

我发现使用嵌入式视图控制器的一种简单方法是为它们添加“占位符”属性,并在“执行”转场时设置这些属性。

// MyContainerController.h
@property (strong, nonatomic) MyLocationFilterController *detailViewController;
@property (strong, nonatomic) UITableViewController *masterViewController;

// MyContainerController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    if([segue.identifier isEqualToString:@"locationEmbedSegue"])
    
        UINavigationViewController *dest = (UINavigationViewController *)segue.destinationViewController;
        self.detailViewController = dest.topViewController;
    
    else if([segue.identifier isEqualToString:@"tableEmbedSegue"])
    
        self.masterViewController = (UITableViewController *)segue.destinationViewController;
        [self.masterViewController.tableView setDelegate:self.detailViewController];
    

【讨论】:

这种方法存在潜在问题。如果首先调用“tableEmbedSegue”,则 self.detailViewController 将为空。我通过实验发现第一个调用的segue 是连接到主视图的子视图中第一个列出的容器视图(在IB 屏幕左侧的场景列表中)。因此,请确保连接到“locationEmbedSegue”的容器视图位于顶部——如果不是,只需将其向上拖动即可。另外我认为最后一行的委托分配是向后的——应该是 self.detailViewController.delegate = self.masterViewController 我认为委托分配没有错误,我将编辑代码以设置 UITableView 的委托而不是 UITableViewController 但除此之外似乎对。 嘿!像魅力一样工作。设置一个属性然后将视图分配给它们的好主意,这样我就可以在整个应用程序中保留它们的引用。非常感谢!【参考方案2】:

我最近来这个问题,发现上面的答案可能有一个问题。

将 setDelete: 方法移出。这确保没有控制器是 nil。

那么代码就变成了:

// MyContainerController.h
@property (strong, nonatomic) MyLocationFilterController *detailViewController;
@property (strong, nonatomic) UITableViewController *masterViewController;

// MyContainerController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

    if([segue.identifier isEqualToString:@"locationEmbedSegue"])
    
        UINavigationViewController *dest = (UINavigationViewController *)segue.destinationViewController;
        self.detailViewController = dest.topViewController;
     else if([segue.identifier isEqualToString:@"tableEmbedSegue"])
    
        self.masterViewController = (UITableViewController *)segue.destinationViewController;

    

    [self.masterViewController.tableView setDelegate:self.detailViewController];

【讨论】:

为什么不直接做 self.masterViewController.tableView.delegate = self;委托不需要与数据源是同一控制器。

以上是关于在嵌入在两个独立容器控制器中的视图之间实现委托的主要内容,如果未能解决你的问题,请参考以下文章

UIStoryboardSegue 嵌入

从容器视图中的选项卡栏控制器中的视图控制器委派信息

响应者链但不是委托属性将值从容器传递回视图控制器

如何在 swift 中从父视图访问容器视图子视图

从嵌入在容器视图中的视图控制器中分离

如何在 Swift 中正确实现不同视图控制器之间的协议和委托?