不要把這裡的通知和推送通知或者本地通知搞混了,這裡的通知是基於訂閱-發佈模型的,即一個物件 (發佈者) 向其他物件 (訂閱者) 發送消息。
發佈者永遠不需要知道訂閱者的任何數據。
Apple 對於通知的使用很頻繁,比如當鍵盤彈出或者收起的時候,系統會分別發送 UIKeyboardWillShowNotification/UIKeyboardWillHideNotification 的通知。當你的應用切到後台的時候,又會發送 UIApplicationDidEnterBackgroundNotification 的通知。
注意:打開 UIApplication.swift 檔案,在檔案結尾你會看到二十多種系統發送的通知。
打開 FlickrModel.swift 然後先在類別宣告的下一行先加入一個靜態常數字串:
Copy static let FLICKR_DATA_COMPLETE: String = "flickrDataComplete" 為了避免「通知事件名稱」的誤寫,所以預先定義一個靜態常數字串。
然後我們追加一個專門發送系統通知的程式:
Copy private func postFlickrDataCompleteNotification ( aPageIndex : UInt ){
let _userObject:[NSObject : AnyObject ] = [ "pageIndex" : aPageIndex]
NSNotificationCenter. defaultCenter () . postNotificationName ( FlickrModel.FLICKR_DATA_COMPLETE, object : self, userInfo : _userObject )
} 只要執行postFlickrDataCompleteNotification(aPageIndex:UInt),就會發送一個名稱為FlickrModel.FLICKR_DATA_COMPLETE的通知。
然後我們在每一次的 Flickr 資料載入完成後,就執行一次這支程式來透過NSNotificationCenter.defaultCenter()發送通知,也就是onLoadFlickrDataCompleteHandler裡面的最後一行。
Copy private func onLoadFlickrDataCompleteHandler ( aRequest :NSURLRequest ? , aResponse :NSHTTPURLResponse ? , aResult :Result < AnyObject > ){
var _vos:[PhotoVO] = [PhotoVO] ()
var _pageIndex: UInt = 0
if aResult. error == nil {
// 中間略
print ( "LoadFlickrDataComplete!count: \(_vos. count ) " )
} else {
print ( "loadFlickrData Error: \(aResult. error ) " )
}
postFlickrDataCompleteNotification ( _pageIndex )
} 而我們載入 Flickr 的圖片庫資料時,他給我們的每一頁照片資訊我們已經放到字典裡面,儲存在記憶體中,沒有必要每一次都要再更新資料,所以我們可以再把loadFlickrData(aPageIndex:UInt)這支程式再做一下修改,判斷如果字典裡已經有資料的話,就不用再下載了,然後發送通知,如果沒有下載過,就下載資料。
然後再打開 MainViewController.swift , 把之前註解的mPhotoViews反註解,並鍵入如下程式碼:
之前我們是等 Console 顯示 LoadFlickrDataComplete!count:99 之後,確定載入完成,再「手動按下按鈕」,讓 PhotoView 去做圖片載入的動作,這一次我們透過觀察者模式來完成這些事情。
現在的 PhotoModel 已經會透過NSNotificationCenter.defaultCenter()發送FlickrModel.FLICKR_DATA_COMPLETE通知了,所以讓MainViewController當觀察者去觀察NSNotificationCenter.defaultCenter()這個單一設計模式的實體何時會 發送這樣的通知。
每當 FlickrModel 發出一個 FlickrModel.FLICKR_DATA_COMPLETE 通知的時候,由於 MainViewController 已經註冊了成為觀察者,所以系統會調用 onFlickrDataCompleteHandler: 方法。
但是,在實現 onFlickrDataCompleteHandler: 之前,我們必須先在 dealloc 取消監聽。如果沒有取消監聽消息,消息會發送給一個已經銷毀的物件,導致應用程式閃退。
在 MainViewController.swift 加上取消訂閱的程式碼:
當物件銷毀的時候,把它從所有消息的訂閱列表裡去除。
然後再完成onFlickrDataCompleteHandler::
只要收到FlickrModel.FLICKR_DATA_COMPLETE,就會執行onFlickrDataCompleteHandler(aNotification: NSNotification),把通知裡面包含的userInfo字典裡面的pageIndex取出,再從FlickrModel的實體撈取資料,再把圖片資料的網址分別給予畫面上的PhotoView。
我們來回顧一下目前所做的流程:
FlickrModel 負責處理最開始要載入的全部圖片資料,包含圖片網址等。
FlickrModel 裡面完成 Flickr資料載入,但是我們不要別的類別再去操作。
資料載入完以後,再發送通知說FlickrModel.FLICKR_DATA_COMPLETE
MainViewController 當觀察者,負責觀察 NSNotificationCenter的實體 有沒有發送FlickrModel.FLICKR_DATA_COMPLETE這個通知。
MainViewController 知道 NSNotificationCenter 發送了FlickrModel.FLICKR_DATA_COMPLETE這個通知後,開始載入圖片。
再回顧一下,我們使用外觀模式隱藏了下載圖片資料的複雜程度。通知的發送者NSNotificationCenter並不在乎圖片是如何從網上下載的。
現在運行一下專案,可以看到基本縮圖已經顯示出來了:
不過出了問題:這個用來提示加載網絡請求的小菊花怎麼一直在顯示!
我們在PhotoView建立實體後,然後開始載入圖片時,開啓了這個白色小菊花,但是在圖片下載完畢的時候我們並沒有停掉它。我們可以在每次下載成功的時候關閉它,但是我們不這樣做,這次我們來用用另一個觀察者模式: KVO 。
完成到這一步的Demo: