尝试更好地了解iOS delegation
。我使用UIImagePickerController
作为参考,但使用委托来解除我的视图控制器是一个很好的代码示例?
我有一个 TabBarViewController调用AViewController ,并想使用delegation
来解除AViewController。
答案 0 :(得分:0)
在这种情况下,想法是呈现新viewcontroller的类也应该是解析它的类。 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的任何用户在使用它之前必须同意的协议。同样地,你不能使用UITableView来观察UITableViewDelegate和UITableViewDataSource协议(这是两个独立的协议)。
任何想要呈现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的唯一连接 - 这就是这里的重点:子类真的不应该知道很多关于使用它们的类。< / p>
最后,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可以不受任何数据处理活动的影响。
尽可能简单地说出来。我希望我没有在这里发生任何错别字: - )