与容器视图通信的最佳实践是什么? [英] What are the best practices on communicating with container views
问题描述
我最近经常使用容器VC,我一直想知道主Vc和容器VC之间的最佳通信方式是什么。现在我正在使用通知,但我宁愿使用更好的东西。如何获取指向容器VC的指针,以便至少可以使用委托?有没有更好的方法?
容器视图控制器可以在自身和嵌入式视图控制器之间建立任何必要的连接,在其 prepareForSegue:sender:
方法。
在iOS编程中,我们有这种沟通方式的模式视图控制器之间。您可以在
<我不确切知道这个应用程序是如何实现的。但是我们假设有一个顶级的
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(非原子,弱)id< MapViewControllerDelegate>代表;
- (void)setMarkers:(NSArray *)标记;
- (void)zoomToMarker:(MapMarker *)marker;
@end
请注意委托
属性是弱
以避免保留周期。
AppViewController
需要符合 MapViewControllerDelegate
协议。通常我们在 AppViewController.m
中声明类扩展中的一致性,因为一致性不需要是 AppViewController
的公共界面。 AppViewController
还需要引用 MapViewController
。
@interface AppViewController()< MapViewControllerDelegate>
@property(非原子,强)MapViewController * mapViewController;
@end
接下来,我们进入故事板,选择嵌入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;
//我们可以在mapViewController上做任何额外的设置,
//就像设置它的初始视口一样。
}
请注意 AppViewController
还必须实现 mapviewController:didSelectMarker:
,并且 MapViewController
需要实现 setMarkers:
和 zoomToMarker:
。
I have been using container VCs often recently and I have been wondering what is the best way to communicate between the main Vc and the container VCs. Right now im using notifications, but I would rather use something better. How can I obtain a pointer to the container VCs so that I can at least use delegation? Any better ways?
It is up to the container view controller to set up any necessary connections between itself and the embedded view controller, in its prepareForSegue:sender:
method.
In iOS programming, we have a pattern for this style of communication betwixt view controllers. You can read about it in "Coordinating Efforts Between View Controllers" in the *View Controller Programming Guide for iOS".
But I think it's easier to understand with a concrete example. Let's use the Google Maps app for iPhone:
I don't know exactly how this app is implemented. But let's suppose there's a top-level AppViewController
that manages the search bar (at the top) and the location bar (at the bottom), and it embeds a MapViewController
in a container view.
There are some interactions between the view controllers. When the user searches, the AppViewController
needs to tell the MapViewController
to place some map markers and zoom in on one of them. When the user taps a map marker, the MapViewController
needs to tell the AppViewController
to display information about that marker in the location bar at the bottom.
So here's the pattern.
First, we define a protocol for the messages that the MapViewController
(which is the embedded view controller) will send to the AppViewController
(which is the container view controller):
@class MapMarker;
@class MapViewController;
@protocol MapViewControllerDelegate <NSObject>
- (void)mapViewController:(MapViewController *)mapViewController didSelectMarker:(MapMarker *)marker;
@end
We will make the AppViewController
conform to this protocol. So the MapViewController
doesn't need to know about the AppViewController
specifically. It just needs a reference to some object that conforms to the protocol. The MapViewController
also needs to understand a message that sets its markers and a message that zooms to a specific marker. So we declare MapViewController
like this:
@interface MapViewController : UIViewController
@property (nonatomic, weak) id<MapViewControllerDelegate> delegate;
- (void)setMarkers:(NSArray *)markers;
- (void)zoomToMarker:(MapMarker *)marker;
@end
Note that the delegate
property is weak
to avoid a retain cycle.
The AppViewController
needs to conform to the MapViewControllerDelegate
protocol. Usually we declare that conformance in a class extension in AppViewController.m
, since conformance doesn't need to be part of AppViewController
's public interface. The AppViewController
also needs a reference to the MapViewController
.
@interface AppViewController () <MapViewControllerDelegate>
@property (nonatomic, strong) MapViewController *mapViewController;
@end
Next, we go into the storyboard, select the embed segue, and give it an identifier:
Now we can implement the prepareForSegue:sender:
method to wire up the properties:
@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.
}
Note that AppViewController
also has to implement mapviewController:didSelectMarker:
, and MapViewController
needs to implement setMarkers:
and zoomToMarker:
.
这篇关于与容器视图通信的最佳实践是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!