在这种情况下,想法是呈现新视图控制器的类也应该是关闭它的类。 AViewController 可能不知道它是如何呈现的,所以它想让呈现器 TabBarViewController 以任何需要的形式处理解除。因此,我们需要定义一个协议,比如 AViewControllerProtocol,它允许对解除调用有一个标准定义:
这在 AViewControllerProtocol.h 中:
@protocol AViewControllerProtocol <NSObject>
@required
- (void) dismissWithDone:(UIViewController *)viewController;
- (void) dismissWithCancel:(UIViewController *) viewController;
@optional
- (void)dismissWithDone:(UIViewController *)viewController andPlaySoundFile:(NSString *)soundPath;
@end
这在一个名为 AViewControllerProtocol.h 的文件中。 TabBarViewController.m 和 AViewController.m 都会导入它。将此视为 AViewController 的任何用户必须同意才能使用它的协议。同样,如果没有约定遵守 UITableViewDelegate 和 UITableViewDataSource 协议(它们是两个独立的协议),您也不能使用 UITableView。
任何想要呈现 AViewController 的类,都可以从协议定义中看到 AViewController 需要两个必需的方法才能被正确地解除。它还有一个可选的第三种方法,请求演示者在关闭后播放声音。
为了让 AViewController 履行其职责,它需要获取并存储有关演示者是谁的信息。那就是所谓的委托。委托是在AViewController的@interface中定义的一个属性,在AViewController.h中:
这在 AViewController.h 中:
@property (nonatomic, weak) id<AViewControllerProtocol> delegate;
现在,演示者 TabBarViewController 需要发挥作用。它需要定义两个必需的方法,加上可能是最优的一个,还需要设置委托值:
在 TabBarViewController.m 中,在 @implementation 中:
这在 TabBarViewController.m 中:
- (void) dismissWithDone:(UIViewController *)viewController
{
[self saveData:viewController.dataToSave]; // this could be the results that need to be saved
[viewController dismissViewControllerAnimated:YES completion:^{
;
}];
}
- (void) dismissWithCancel:(UIViewController *)viewController
{
// don't save data
[viewController dismissViewControllerAnimated:YES completion:^{
;
}];
}
委托值是在 AViewController 首次创建和/或呈现之前设置的:
这也在 TabBarViewController.m 中:
AViewController * aVC = [AViewController.alloc init];
aVC.delegate = self;
aVC.data = ...; // this may be the data you want changed by the VC
[self presentViewController:aVC animated:YES completion:^{
}];
在这里设置委托是 AViewController 类与其呈现的 viewController 的唯一连接——这就是这里的重点:子类真的不需要知道很多关于使用它们的类。
最后,AViewController 类需要添加以下内容,以便通过委托调用回呈现类 - 所以在 AViewController.m 中:
这在 AViewController.m 中:
-(IBAction)userHitButton:(id)sender
{
if (sender == doneButton) {
if ([_delegate respondsToSelector:@selector(dismissWithDone:)]) {
[_delegate dismissWithDone:self];
}
} else {
if ([_delegate respondsToSelector:@selector(dismissWithCancel:)]) {
[_delegate dismissWithCancel:self];
}
}
}
如果你想知道为什么调用类必须:
aVC.delegate = self;
这是因为在某些情况下,实际创建子类的类不是处理委托调用的类。在这种情况下,您可以放置一个将处理委托回调的类的实例,而不是 self。例如,假设您有 AViewController、BViewController 和 CViewController。他们都从用户那里获取需要保存的数据。假想名称为 ABCDataHandler 的类可以处理dismissWithDone: 和dismissWithCancel: 回调并根据需要保存数据,并且TabBarViewController 可以远离任何数据处理活动。
尽可能简单地说。我希望我没有在这里打错字:-)