起初我以为我只需要以一个segue序列从一个ViewController向另一个,向前和向后发送信息时实现这个模式。
但是现在我已经尝试将信息从父视图控制器发送到子视图控制器,并发现我需要协议/委托以便由于某种原因发回信息,尽管没有涉及segue,它全部在相同的“页面。”
我在这里缺少一些原则或规则吗?
答案 0 :(得分:1)
协议/委托是在任意两个对象之间传递信息的一种方式。例如,从互联网下载大型文件的类和视图控制器,然后视图控制器将下载的信息呈现给用户。根据MVC模式,我们不想在下载类中处理下载信息的显示,因此我们需要以某种方式传递信息。
// Downloader.m
- (NSData *)download {
/* do work */
return downloadedInformation;
}
然后,在我们的视图控制器中:
// ViewController.m
#import "Downloader.h"
/* ... */
- (void)viewWillAppear {
self.data = [[Downloader sharedInstance] download];
}
这会遇到一些问题。我们将挂起主队列(冻结的UI),因为下载正在主线程上运行并需要一些时间,因此我们需要在后台执行它。但是如果我们在后台执行下载,获取下载信息并不像从函数返回值那么容易。
// Downloader.m
- (NSData *)download {
NSData *downloadedInformation;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
/* do work asynchronously */
}
return downloadedInformation; // will return before download is done
}
因此,我们需要一种方法可以在课程可用时将这些信息传递给所有课程,但我们不知道它何时可用。执行此操作的一种方法是委托回调。假设我们的viewController有一个公共方法downloadFinished:
,它接受一个参数data
。
// Downloader.m
#import ViewController.h
/* ... */
- (void)download:(ViewController *)viewController {
NSData *downloadedInformation;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
/* run download asynchronously, which will take a while */
// assign downloadedInformation once download is completed,
// guaranteeing that it is valid data
// callback on main queue
dispatch_async(dispatch_get_main_queue(), ^{
[viewController downloadFinished:downloadedInformation];
}
}
}
现在,我们不是返回一个值,而是将其作为参数传递给ViewController
中的方法。然后,在ViewController
:
- (void)downloadFinished:(NSData *)data {
[self updateUIWithData:data]; // update UI
}
那么协议和代表在哪里进来?假设您想在另一个类中调用downloadFinished:
,可能是也可能不是视图控制器。 Downloader
类实际上并不需要知道哪种对象正在接收回调,它只需要知道对象(我们将调用该委托)响应选择器{{ 1}}。因此,我们定义了一个需要方法downloadFinished
的协议。
downloadFinished:
然后我们可以说我们的ViewController符合这个协议:
@protocol DownloaderDelegate
- (void)downloadFinished:(NSData *)data;
@end
在我们的Downloader类上定义一个委托:
// ViewController.h
@interface ViewController: UIViewController <DownloaderDelegate>
并重写我们的函数以接受符合我们的委托的任何对象,而不仅仅是ViewController的实例。
// Delegate.h
/* ... */
@property(weak) id<DownloaderDelegate> delegate;
现在我们使用委托模式在类之间传递信息。如果您仍然感到好奇,Apple的文档会有更多的阅读。