一款輕量級的 iOS 映像緩衝

來源:互聯網
上載者:User

標籤:

我們的 iOS 應用都包含了大量的映像。建立富有吸引力的視圖,主要依賴於大量的裝飾圖片,所有這些首先必須從遠程伺服器擷取。如果每次開啟應用都要從伺服器一次又一次的擷取每個映像,那麼使用者體驗肯定達不到好的效果,所以本機快取遠程映像是非常有必要的。

葉秀蘭
翻譯於 1年前

0人頂

 

頂 翻譯的不錯哦!

版本1-尋找一張圖片,並從磁碟上讀取它

我們的第一個圖片緩衝是簡單但是有效。從緩衝中尋找每一個我們曾經訪問過的圖片,用遠端URL作為緩衝的索引值。如果本地的磁碟緩衝時有效,從磁碟中讀取檔案並建立UIImage,並立即返回。如果再磁碟上沒有找到檔案,非同步從遠程URL擷取檔案,緩衝到磁碟,然後返回一個建立的UIImage。

目前這對於我們的使用是完全滿足了。但是它有一個不必要的弱點:每次緩衝請求都需要從磁碟讀取圖片,效能都消耗在對磁碟的訪問和圖片檔案的解碼上了。

地獄星星
翻譯於 1年前

0人頂

 

頂 翻譯的不錯哦!

版本 2 - 內存緩衝

謝天謝地,蘋果的UIImage有內建的記憶體緩衝。所以,你只需修改一行代碼,圖片就能從磁碟緩衝改為記憶體緩衝。

當你使用imageNamed:擷取UIImage的時候,它第一步就是檢查自己的記憶體看看是否已經載入過這個圖片。如果這樣,你不用任何系統花銷就能得到一個UIImage執行個體。所以把原本這樣的寫法替換掉:

return [UIImage imageWithContentsOfFile:[self absolutePathForURL:url]];

我們可以零花銷去訪問記憶體緩衝,用下面的代碼就可以了:

return [UIImage imageNamed:[self relativePathForURL:url]];

UIImage  會尋找它的記憶體緩衝,如果找到,就會零消耗地返回這個照片. 如果沒有找到,這張照片就會從磁碟載入,消耗一定的系統效能。 

美其名曰
翻譯於 1年前

0人頂

 

頂 翻譯的不錯哦!

版本3 —— 擷取隊列、資料預取和變數催促

當改進應用程式設計時我們渴望更多的圖片元素,渴望更炫的畫面,更大的圖片,更多的圖片。

讓這些大圖儘可能快的顯示在螢幕上對使用者體驗來說是至關重要的,而只是簡單地在每次需要顯示的時候去緩衝當中抓取圖片資料是不能夠解決問題的。大圖需要更多的時間才能從網路上載入回來,並且一次請求太多的圖片會導致所有圖片都來不及載入。需要仔細考慮什麼時候去檢查緩衝當中有無圖片資料以及什麼時候從網路上抓取圖片。我們需要預緩衝和抓取列陣。

jiangguo
翻譯於 11個月前

0人頂

 

頂 翻譯的不錯哦!

快速隊列和慢速隊列

我們設定了兩個隊列,一個串列,一個並行。在螢幕上被迫切要求的圖片進入並行隊列(fastQueue),可能晚點才需要的圖片進入串列隊列(slowQueue)。

就UITableView的實現而言,這意味著在螢幕上的表格單元從fastQueue擷取圖片, 每個關閉的螢幕行的圖片從slowQueue預先載入。

地獄星星
翻譯於 1年前

0人頂

 

頂 翻譯的不錯哦!

現在不需要處理圖片

假設我們要從伺服器上請求包含30條事件的一頁資訊回來,一旦這些內容請求回來時我們就可以排隊等待預取其中的每一張圖。

- (void)pageLoaded:(NSArray *)newEvents {        for (SGEvent *event in newEvents) {               [SGImageCache slowGetImageForURL:event.imageURL thenDo:nil];        }}

slowGetImageForURL:這個方法將圖片添加到slowQueue這個隊列當中,允許它們在不阻塞網路通訊的前提下被一張一張的取出來。

thenDo:這個代碼塊在這裡是沒有被實現,是因為我們目前還不需要對圖片做任何事情。所有我們需要做的就是確保它們在本地磁碟緩衝當中,並且隨時準備在螢幕上滑動表格時來使用。

jiangguo
翻譯於 11個月前

1人頂

 

頂 翻譯的不錯哦!

現在就要處理圖片

顯示在螢幕上的表格希望立即顯示它們的圖片,所以在table cell子類當中實現:

- (void)setEvent:(SGEvent *)event {        __weak SGEventCell *me = self;        [SGImageCache getImageForURL:event.imageURL thenDo:^(UIImage *image) {               me.imageView.image = image;    }    ];}

getImageForURL:這個方法將抓取圖片的過程添加到fastQueue這個隊列當中,意味著只要iOS系統允許,它們會並行被地執行。如果抓取圖片的過程已經存在於slowQueue隊列當中,它會被移動到fastQueue隊列中,從而避免重複請求。

jiangguo
翻譯於 11個月前

0人頂

 

頂 翻譯的不錯哦!

一直非同步

等等,getImageForURL:不是一個非同步方法呼叫嗎?如果你明知道圖片已經在緩衝中,但是卻不想在主線程上立即使用它嗎?直覺告訴你那是錯誤的。

從磁碟上載入圖片太費資源,同樣解壓圖片也會費很多資源。可以在滑動的過程當中進行配置和添加表格,這最後一件你想在滑動表格時做的事是很危險地,因為它會阻塞主線程,會有卡頓的現象出現。

使用getImageForURL:可以讓磁碟載入的動作脫離主線程,於是當thenDo:這個用於收尾工作的代碼塊執行的時候它已經有了一個UIImage執行個體,從而不會有滑動卡頓的危險。如果圖片已經存在於本機快取當中,用於收尾工作的代碼塊會在下一次運行周期執行,並且使用者不會注意到兩者之間的差別。他們會注意到的是滑動不會卡頓了。

jiangguo
翻譯於 11個月前

0人頂

 

頂 翻譯的不錯哦!

現在,不需要你快速執行

如果使用者很快的滑動表格到底部,幾十或幾百個表格單元會出現在螢幕上,並向fastQueue請求圖片資料,然後很快地從螢幕上消失。突然間這個並行地隊列會將大量實際上不再需要的圖片請求充斥進網路。當使用者最終停止滑動時,那些當前螢幕上相應的表格單元視圖會將它們的圖片請求至於那些並不急需的請求後面,因此網路阻塞了。

這就是 wheremoveTaskToSlowQueueForURL:這個方法的產生的原因.

// a table cell is going off screen- (void)tableView:(UITableView *)table        didEndDisplayingCell:(UITableViewCell *)cell        forRowAtIndexPath:(NSIndexPath*)indexPath {         // we don‘t need it right now, so move it to the slow queue                  [SGImageCache moveTaskToSlowQueueForURL:[[(id)cell event] imageURL]];}

這確保在fastQueue中的只會有真正需要被快速執行的任務。任何以前認為需要快速執行但現在不需要的任務會被移至slowQueue中。

jiangguo
翻譯於 11個月前

0人頂

 

頂 翻譯的不錯哦!

重點和選擇

已經有相當多的iOS圖片緩衝庫。它們中一些庫只針對某些應用情境,一些庫提供了不同情境一定的可擴充性。我們的庫即沒有專門針對某些應用情境,也沒有太多大而全的特性。針對我們的使用者我們有三類基本的重點:

重點 1: 最好的幀率

很多的庫都非常專註在這一點上,使用一些高度定製和複雜的方法,儘管基準沒有決定性地顯示這樣有效。我們發現最好的幀率由這些決定:

  1. 將對磁碟的訪問(並且幾乎其它的所有)脫離主線程。

  2. 使用UIImage的記憶體緩衝來避免不必要的磁碟訪問和圖片解壓。

jiangguo
翻譯於 11個月前

0人頂

 

頂 翻譯的不錯哦!

重點 2: 讓最最重要的圖片優先顯示

大多數的庫都考慮讓隊列管理成為別人關心的事。對於我們的應用,這幾乎是最重要的點。

讓正確的圖片在正確的時間顯示在螢幕上可以歸結為一個簡單的問題:“我們現在就需要它顯示還是過一會兒?”。那些需要立即顯示的圖片是並行載入地,而其它所有東西都被添加到串列隊列中。所有之前急迫的事但現在不急迫的話就會從fastQueue分到slowQueue中。並且當fastQueue在工作時,slowQueue是處於掛起狀態的。

這讓那些急需顯示的圖片可以單獨訪問網路,同時也確保了一張非急需顯示的圖片可以在過一會成為一張急需顯示的圖片,因為它已經存到了緩衝當中,隨時準備用於顯示。

jiangguo
翻譯於 11個月前

0人頂

 

頂 翻譯的不錯哦!

重點 3: 儘可能簡單的API

大多數庫都做到了這一點。許多庫為了隱藏細節內容而提供了UIImageView的分類,並且許多庫讓抓取一張圖片的流程變得儘可能的便利。針對我們經常做的三件事,我們的庫選定了三個主要的方法:

快速抓到一張圖

__weak SGEventCell *me = self;[SGImageCache getImageForURL:event.imageURL thenDo:^(UIImage *image) {    me.imageView.image = image;}];

排隊等待一張我們一會才需要的圖片

[SGImageCache slowGetImageForURL:event.imageURL thenDo:nil];

通知緩衝一張急需顯示的圖已經不需要立刻顯示

[SGImageCache moveTaskToSlowQueueForURL:event.imageURL];
結論

通過專註於預取,隊列管理,從主線程移除耗時的任務,並且依賴於UIImage內建的記憶體緩衝,我們努力從一個簡單的軟體包中得到好的結果。

一些有用的連結
  • SGImageCache on GitHub

  • SGImageCache on CocoaPods

  • SGImageCache on CocoaDocs

一款輕量級的 iOS 映像緩衝

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.