Learning Flyweight pattern by using MKAnnotationView

在 iPhone app 上面如果我們要使用地圖,在地圖上面希望插著紅色針頭,針頭要很可愛的從上方往下掉下來的效果之外,也希望可以按下它之後彈出一個浮出視窗,小浮出視窗希望可以稍微客製化,顯示自己要呈現的訊息等等,而且因為希望插滿各種不同座標的針頭,且要可以一口氣顯示在畫面上,這樣子我們做的到嗎?這需求很合理阿,例如如果今天是開發一個導航系統、同學住家通訊錄搭配地圖顯示等等都會有這樣需求。我們來解析一下這該如何辦到,另外從中學習 Flyweight pattern。

如果我們使用預設的 MKMapView ,並且使用 addAnnotations 將座標物件們當作陣列這樣加進來,會發現僅能做到基本預設的紅色針頭,上面顯現 title 和 sub title,而且它不會有從空飛下的效果,也沒有圖片或者右邊 Disclosure 的按鈕做進一步瀏覽,如此一來還無法滿足上面一段的故事。

在 MKMapViewDelegate Protocol 裡面有一個 optional 的 method 是 mapView:viewForAnnotation: 它可以回傳一個特定的 specified annotation object。文件上說傳入 map view ( 它 request annotation view 的) 和傳入物件 annotation (該次要來顯示的,而且這邊可以來客製化),且最後這個 method 會回傳 MKAnnotationView 加工過的針頭。

另外注意到開發文件上很貼心的說到,與其每次呼叫都建立一個新的 View,我們應該使用 dequeueReusableAnnotationViewWithIdentifier: 來辨識這個是否已經建立了。如果已經建立過一個,只要更新資料舊好就可以把客製化的 annotation 回傳回去。如果這個類別不存在,我們再建立它,客製化成我們要,再回傳。另外也可以從這邊辨別傳進來的座標是不是 user 當前座標,如果是可以另外設定成跟地圖上其他針頭做區別。如果不想客製化,只回傳 nil,那麼就還是基本款而已。

看到以上這段說明,我們看到了 Flyweight pattern 蹤影了。
Flyweight pattern 定義:Use sharing to support large numbers of fine-grained objects efficiently.

Flyweight 是要用來分享物件可以被大量重複使用的,僅是物件外殼重複使用,但是內容還是可以依賴於各個內容值。Flyweight 不知道內容且誰來使用它,僅負責該內部做的事情,如果該物件不存在就建立出來分享,如果存在就直接共享。

Flyweight pattern 在越大量使用情況下就越有效用,適用時機有應用程式大量的使用同一種物件、存取昂貴的物件、應用程式不會在意是不是同一個物件,而是僅需要理面的內容。

所以透過插針且針頭數量會很多情況上,我們來搭配以上的模式來實作我們的 method。


以上這樣的開發不但可以做到客製化外殼,還可以用在相似的針實際內容不同的情境出來,且也符合了操作使用上效能等等議題,是不是也有感覺地圖上萬箭插針從空而降也不擔心了呢?如果想要了解更多,可以參考 MKMapViewDelegate Protocol Reference 的文件。

Comments