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

时间:2013-07-01 02:15:42

标签: ios objective-c

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

1 个答案:

答案 0 :(得分:22)

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

在iOS编程中,我们在视图控制器之间有这种通信方式。您可以在“Coordinating Efforts Between View Controllers” in the *View Controller Programming Guide for iOS”中了解相关信息。

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

Google Maps app for iPhone

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

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

所以这就是模式。

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

@class MapMarker;
@class MapViewController;

@protocol MapViewControllerDelegate <NSObject>

- (void)mapViewController:(MapViewController *)mapViewController didSelectMarker:(MapMarker *)marker;

@end

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

@interface MapViewController : UIViewController

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

- (void)setMarkers:(NSArray *)markers;
- (void)zoomToMarker:(MapMarker *)marker;

@end

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

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

@interface AppViewController () <MapViewControllerDelegate>

@property (nonatomic, strong) MapViewController *mapViewController;

@end

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

embed segue identifier

现在我们可以实现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: