与容器视图通信的最佳实践是什么?

我最近经常使用容器VC,我一直想知道主Vc和容器VC之间的最佳通信方式是什么。 现在我正在使用通知,但我宁愿使用更好的东西。 如何获取指向容器VC的指针,以便至少可以使用委托? 有更好的方法吗?

容器视图控制器在其prepareForSegue:sender:方法中设置自身与嵌入式视图控制器之间的任何必要连接。

在iOS编程中,我们在视图控制器之间有这种通信方式。 您可以在“适用于iOS的View Controller编程指南”中的“在视图控制器之间协调工作”中阅读相关内容。

但我认为用一个具体的例子来理解它会更容易。 让我们使用适用于iPhone的Google地图应用:

适用于iPhone的Google地图应用

我不确切知道这个应用程序是如何实现的。 但是我们假设有一个顶层的AppViewController来管理搜索栏(在顶部)和位置栏(在底部),它在一个容器视图中嵌入了一个MapViewController

视图控制器之间存在一些交互。 当用户搜索时, AppViewController需要告诉MapViewController放置一些地图标记并放大其中一个。 当用户点击地图标记时, MapViewController需要告诉AppViewController在底部的位置栏中显示有关该标记的信息。

所以这是模式。

首先,我们为MapViewController (它是嵌入式视图控制器)将发送到AppViewController (它是容器视图控制器)的消息定义一个协议:

 @class MapMarker; @class MapViewController; @protocol MapViewControllerDelegate  - (void)mapViewController:(MapViewController *)mapViewController didSelectMarker:(MapMarker *)marker; @end 

我们将使AppViewController符合此协议。 因此MapViewController不需要专门了解AppViewController 。 它只需要引用一些符合协议的对象。 MapViewController还需要了解设置其标记的消息和缩放到特定标记的消息。 所以我们像这样声明MapViewController

 @interface MapViewController : UIViewController @property (nonatomic, weak) id delegate; - (void)setMarkers:(NSArray *)markers; - (void)zoomToMarker:(MapMarker *)marker; @end 

请注意, delegate属性weak以避免保留周期。

AppViewController需要符合MapViewControllerDelegate协议。 通常我们在AppViewController.m中的类扩展中声明一致性,因为一致性不需要是AppViewController的公共接口的一部分。 AppViewController还需要对MapViewController的引用。

 @interface AppViewController ()  @property (nonatomic, strong) MapViewController *mapViewController; @end 

接下来,我们进入故事板,选择嵌入segue,并给它一个标识符:

嵌入segue标识符

现在我们可以实现prepareForSegue:sender:方法来连接属性:

 @implementation AppViewController - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"MapEmbedding"]) { [self prepareForMapEmbeddingSegue:segue sender:sender]; } } - (void)prepareForMapEmbeddingSegue:(UIStoryboardSegue *)segue sender:(id)sender { self.mapViewController = segue.destinationViewController; self.mapViewController.delegate = self; // We can do any additional setup on mapViewController here, // like set its initial viewport. } 

注意, AppViewController还必须实现mapviewController:didSelectMarker:并且MapViewController需要实现setMarkers:zoomToMarker: .