版权声明:原创做品,谢绝转载!不然将追究法律责任。设计模式
观察者设计模式网络
在观察者设计模式里面,一个对象通知其余的对象一些状态的改变。涉及这些对象不须要知道另外一个对象---所以鼓励解耦设计模式。这个设计模式常常被用来通知感兴趣的对象当一个属性被改变时候。app
一般实现须要一个观察者注册另外一个对象感兴趣的状态。当状态改变,全部的观察者对象被通知改变了。苹果的远程通知服务就是一个全球性的例子。async
若是你一直坚持MVC的概念,你须要容许你的model对象和View对象通讯,可是不能直接引用,这就是观察者设计模式的由来。ide
cocoa实现观察者有两个类似的方法:通知和键值观察:post
通知:不要被本地通知和远程通知迷惑,通知是根据订阅和通知的模式容许一个对象(通知者)发送消息给另外一些对象(订阅者也就是监听者)。这个通知者不须要知道订阅者的任何信息。编码
苹果公司大量的使用通知,例如当键盘隐藏时候系统发送一个UIKeyboardWillShowNotification/UIKeyboardWillHideNotification通知。当你的应用进入后台系统发送一个UIApplicationDidEnterBackgroundNotification 通知。atom
打开UIApplication头文件。在文件最后你会看到系统发出的20个通知。spa
怎么使用通知呢设计
在AlbumView实现文件里面插入下面代码在[self addSubview:indicator];后面initWithFrame:albumCover:里面
[[NSNotificationCenter defaultCenter] postNotificationName:@"BLDownloadImageNotification"
object:self
userInfo:@{@"imageView":coverImage, @"coverUrl":albumCover}];
这一行经过NSNotificationCenter 的一个单例发送一个通知。这个通知包含了一个UIImageView用来填充专辑封面和一个下载图片的URL。这里面的全部信息你须要在你的下载任务里面执行。
在libraryAPI实现文件里面的init方法isOnline = NO:后面添加下面代码:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(downloadImage:) name:@"BLDownloadImageNotification" object:nil];
这个就是观察者。每次AlbumView 类发送一个BLDownloadImageNotification 通知。这个libraryAPI为这个通知注册一个观察者。系统通知libraryAPI。而且libraryAPI执行downloadImage:做为回答。
而后在实现downloadImage:以前你必须取消你注册的这个通知当你的类销毁的时候。若是不这样作通知就会发送到一个销毁的对象。这就是应用崩溃的结果。
在libraryAPI实现文件里面添加下面代码:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
当这个类销毁时候。他做为观察者从全部已经注册的通知中移除掉。还有一件事情要作,咱们保存下载的图片。这样应用不须要下载相同的图片了。
打开
PersistencyManager有文件加入下面两个方法原型:
- (void)saveImage:(UIImage*)image filename:(NSString*)filename; - (UIImage*)getImage:(NSString*)filename;
实现文件里面:
- (void)saveImage:(UIImage*)image filename:(NSString*)filename { filename = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@", filename]; NSData *data = UIImagePNGRepresentation(image); [data writeToFile:filename atomically:YES]; } - (UIImage*)getImage:(NSString*)filename { filename = [NSHomeDirectory() stringByAppendingFormat:@"/Documents/%@", filename]; NSData *data = [NSData dataWithContentsOfFile:filename]; return [UIImage imageWithData:data]; }
这段代码是下载图片保存在沙盒,而且若是沙盒没有这个图片路径就会返回nil。
下面在libraryAPI加入下面代码:
- (void)downloadImage:(NSNotification*)notification { // 1 UIImageView *imageView = notification.userInfo[@"imageView"]; NSString *coverUrl = notification.userInfo[@"coverUrl"]; // 2 imageView.image = [persistencyManager getImage:[coverUrl lastPathComponent]]; if (imageView.image == nil) { // 3 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ UIImage *image = [httpClient downloadImage:coverUrl]; // 4 dispatch_sync(dispatch_get_main_queue(), ^{ imageView.image = image; [persistencyManager saveImage:image filename:[coverUrl lastPathComponent]]; }); }); } }
具体解释上面代码
1:downloadImage 被执行经过通知所以接收这个通知对象做为参数:
2:若是以前已经下载图片那么从PersistencyManager 检索图片。
3:若是图片没有下载,那么再次用HTTPClient请求图片
4:当下载完成了在UIImageView里面显示图片而且用PersistencyManager 来保存图片。
咱们再次用外观设计模式隐藏从一些类里面下载一个图片的复杂性。这个通知发送者不关心你的图片是从网络获取的仍是从文件系统得到的。
编译运行你的应用看看你的专辑已经覆盖到你的滑动视图上。
再次中止而且运行他。注意没有延迟加载你的专辑由于他们已经保存到本地。你甚至能够断开网络连接你的应用还能够继续的完美运行着。可是你的网络提示器一直的旋转不中止了为何呢?
当你开始下载图片,你没有实现当图片下载完中止网络提示器的旋转的逻辑。你不能每次都发送一个通知当图片下载完成了。然而咱们能够用另外一个观察者设计模式键值编码。