什么是代理?
Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.
意译一下就是:代理是一种简单而功能强大的设计模式,这种模式用于一个对象“代表”另外一个对象和程序中其他的对象进行交互。 主对象(这里指的是delegating object)中维护一个代理(delegate)的引用并且在合适的时候向这个代理发送消息。这个消息通知“代理”主对象即将处理或是已经处理完了某一个事件。这个代理可以通过更新自己或是其它对象的UI界面或是其它状态来响应主对象所发送过来的这个事件的消息。或是在某些情况下能返回一个值来影响其它即将发生的事件该如何来处理。代理的主要价值是它可以让你容易的定制各种对象的行为。注意这里的代理是个名词,它本身是一个对象,这个对象是专门代表被代理对象来和程序中其他对象打交道的。
我在很久之前就学习过代理模式,但是因为用的不多所以经常忘记,因为要工作了我想肯定会经常用代理模式,所以想重新将它捋一下.
在正式开始之前介绍一下这个小demo,整体是一个navigationController,一共有两个VC.第一页创建了一个imageView和跳转到第二页的Btn.第二页只有一个跳转回第一页的Btn,点击这个btn从网页上下载一个图片,然后加载到第一页的imageView上.再跳转回第一页
第一步
在VC2中声明一个delegate协议.协议里是你想要实现的函数,默认是必选的函数.可以在前面加上@optional(可选)
@protocol imageRead <NSObject>
-(void)changeDownloadedImage:(UIImage *)image;
@end
第二步
在VC2.h的声明中创建一个delegate属性变量.属性为nonatomic,assign.在非ARC下是assign,arc下用weak好了。指针就不会释放的。
@property (nonatomic, assign) id <imageRead> delegate;
第三步
在VC2.m中点击返回按钮的函数中实现delegate发送消息
[self.delegate changeDownloadedImage:image];
第四步
回到VC1.h中声明协议为协议.
实现代理函数
-(void)changeDownloadedImage:(UIImage *)image{
[_imageView setImage:image];
}
第五步
在VC1.m中跳转到第二页的时候,设置第二页的代理为第一页:
-(void)clickBtn:(UIButton *)sender{
ViewController1 *vc2 = [[ViewController1 alloc] init];
vc2.delegate = self;
[self.navigationController pushViewController:vc2 animated:YES];
}
这五步步骤不必相同,但是缺一不可,源码在我的资源里,有需要的同学可以拿来看看.
在从网上获取图片时,我第一次用的是AFNetworking框架中的UIKit+UIImageView中的方法:
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure
AFN使用的是多线程的方法,这个库写的确实很干净简洁,在这个函数中先从cache加载url图,若没有缓存,先用placeholder图替代.
于是我就想不用AFN从网上获取,
UIImage *result;
NSData *date = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://img05.tooopen.com/images/20150422/tooopen_sy_119846376592.jpg"]];
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
path = [path stringByAppendingString:@"userInfo"];
[date writeToFile:path atomically:YES];
result = [UIImage imageWithData:date];
[self.delegate changeDownloadedImage:image];
[self.navigationController popViewControllerAnimated:YES];
问题就来了…反面案例:在返回第一页的时候UI会被阻塞,因为dataWithContentsOfURL:方法在下载的时候时间可能会有点长,就像之前翻译的那篇多线程文章说的,这个时候就想到了多线程.把它开辟一个后台队列扔到队列去下载,下载完了通过delegate协议将image传回去:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage *result;
NSData *date = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://img05.tooopen.com/images/20150422/tooopen_sy_119846376592.jpg"]];
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
path = [path stringByAppendingString:@"userInfo"];
[date writeToFile:path atomically:YES];
result = [UIImage imageWithData:date];
[self.delegate changeDownloadedImage:result];
});
[self.navigationController popViewControllerAnimated:YES];
这次就好了,在点击的时候UI不会卡住,而是先跳转回第一页,在image下载完之后会被协议加载出来.