版權聲明:原創做品,謝絕轉載!不然將追究法律責任。設計模式
觀察者設計模式網絡
在觀察者設計模式裏面,一個對象通知其餘的對象一些狀態的改變。涉及這些對象不須要知道另外一個對象---所以鼓勵解耦設計模式。這個設計模式常常被用來通知感興趣的對象當一個屬性被改變時候。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 來保存圖片。
咱們再次用外觀設計模式隱藏從一些類裏面下載一個圖片的複雜性。這個通知發送者不關心你的圖片是從網絡獲取的仍是從文件系統得到的。
編譯運行你的應用看看你的專輯已經覆蓋到你的滑動視圖上。
再次中止而且運行他。注意沒有延遲加載你的專輯由於他們已經保存到本地。你甚至能夠斷開網絡連接你的應用還能夠繼續的完美運行着。可是你的網絡提示器一直的旋轉不中止了爲何呢?
當你開始下載圖片,你沒有實現當圖片下載完中止網絡提示器的旋轉的邏輯。你不能每次都發送一個通知當圖片下載完成了。然而咱們能夠用另外一個觀察者設計模式鍵值編碼。