国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

利用內存結構及多線程優化多圖片下載(IOS篇)

2019-11-14 18:43:05
字體:
來源:轉載
供稿:網友

利用內存結構及多線程優化多圖片下載(IOS篇)

前言

下載地址, 后續發布, 請繼續關注本blog

在IOS中,我們常常遇到多圖片下載的問題。最簡單的解決方案是直接利用別人寫好的框架。但是這如同練武,只練外功而不練內功。在這些框架中,SDWebImage這個框架是比較常用的框架,對于該框架的使用,不在這再做詳細介紹。主要從計算機的視角和多線程引發的一些問題來分享下如何自己做,或者說SDWebImage大體上也是基于這種方式來做的。在這之前,有必要先說下一些操作系統的基本架構和原理。

內存結構

其實在操作系統中,所謂的內存結構,不是指我們電腦中的內存。在專業術語中,電腦中的內存稱為主存。而內存結構指的是由磁盤+主存+緩存構成的結構。在這個構架中,從磁盤的速度比主存的速度慢,而主存的速度又比緩存的速度慢。這三種存儲物質也是由不同的材料所做成,所以緩存的價格大于主存的價格,而主存又大于磁盤的價格。要不然你都可以把電腦磁盤替換成內存了,那將是十分的快,當然的保證你電腦是不斷電的。所以程序啟動的時候,都是從磁盤中讀取數據,到主存中完成整個程序的加載,這時候,程序就在主存中。

重點

同樣的道理,我們在做App的時候,對于圖片下載這種問題。我們深知,必須得使用多線程來下載圖片,然后另外一個線程來刷新界面。這才不會導致因為下載事件過長而引起的界面十分不流暢。同時,我們為了避免重復的下載圖片,為用戶節省流量,并且也為了提高圖片的加載速度。我們有必要利用內存結構的特點來解決這個問題。所以對于這種問題,我們主要的思路就是1.將下載的圖片緩存到主存中開辟的一塊緩存圖片的空間。進行UI渲染的時候到緩存中取到對應的圖片,渲染UI界面。

判斷邏輯過程如下:

1.先判斷主存緩存中有沒有圖片,如果沒有進行第二步

2.判斷磁盤有沒有緩存的圖片,如果有將其加載進內存,并緩存到主存中的緩存圖片的位置。如果沒有進行第三步

3.從網絡中下載圖片,并緩存到內存和磁盤上。

4.應用程序需用用到圖片的時候,直接從內存中的緩存圖片的位置拿。

存在的問題:

A.第一個是需要用子線程來下載圖片,主線程進行渲染, 從而提高程序流暢性。

B.第二個是解決因為圖片過大或者圖片數據下載過慢時候,圖片還沒有下載完,還沒緩存到內存中時候。用戶不斷拖拽TableView,

由于UITableViewCell循環利用,使得在進行判斷1的時候,重復下載圖片。


C.第三個是將主存中的圖片緩存寫入磁盤在渲染UI之前,但是我們可以為期在開個線程讓兩個同時進行,提高程序的效率。

對于第一個問題,很好解決。請看代碼, 這是自定義cell中針對傳入模型數據進行的處理。只需關注該重點,想要測試程序自行到我的github上下載,如果你覺得這個程序對你有學習價值,記得給個star。

因為不想重復的粘貼代碼,所以以下代碼是最終版本的核心代碼,但是為了說明問題。問題重現,所以請跟著我的步驟來,一步步的打開被注釋的代碼,觀察效果。現在請你忽略所有注釋的代碼,先搞懂這是為了解決問題A。

- (void)setApp:(SWPApp *)app {        _app = app;        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{                // 1.子線程下載數據        SWPCache * cache = [SWPCache sharedInstance];                // 1.1內存無緩存       // if ( cache.imageCache[app.icon] == nil ) {                                    NSString * folderPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];                        NSString * filePath = [folderPath stringByAppendingPathComponent:[app.icon lastPathComponent]];                        BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath: filePath];                        if (!fileExists) [self loadImageWithURLOrFilePath:app.icon isFilePath: NO]; // 1.2 磁盤無緩存則從網絡下載            else [self loadImageWithURLOrFilePath:filePath isFilePath: YES]; // 1.3 磁盤有緩存, 直接加載進內存中的緩存      // }              //  [NSThread sleepForTimeInterval: 1];                // 2.主線程渲染cell的UI        dispatch_async(dispatch_get_main_queue(), ^{                       self.textLabel.text = app.name;                    self.imageView.image = cache.imageCache[app.icon];                        self.detailTextLabel.text = app.download;                    });                    });    }- (void)loadImageWithURLOrFilePath:(NSString *)url isFilePath:(BOOL)isFilePath {            SWPCache * cache = [SWPCache sharedInstance];    NSData * data = nil;    // 1.先判斷下載該圖片的操作是否已經執行過    // 如果執行過, 那么圖片緩存中必定存在圖片.   // if (!cache.OperationCache[self.app.icon]) {        static int i = 0;        NSLog(@"---%d", i);        data = isFilePath ? [NSData dataWithContentsOfFile: url]                          : (i++, [NSData dataWithContentsOfURL: [NSURL URLWithString: url ]]);                // 如果數據下載失敗        if (!data) {                        [cache.operationCache removeObjectForKey: self.app.icon];                    } else {                    UIImage * image = [UIImage imageWithData: data];                        cache.imageCache[self.app.icon] = image;                        cache.operationCache[self.app.icon] = [NSNumber numberWithBool: true];                                    //  if (!isFilePath) {                // 1.為讓其一邊顯示一邊寫入                //dispatch_async(dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{                    [data writeToFile:url atomically: YES];               //  });           // }                    }                  //  }    }

解決完UI界面的流暢度問題,我們就需要利用內存結構來節約用戶流量和提高UI再次渲染的速度。

所以此時,還沒將圖片緩存到主存中,所以請看下面動態圖。再將第12,24行打開,再看第二種動態圖會發現,打印值只到16,也就是所只下載了16次圖片。這就大大提高了的說明了能節約用戶流量和提高UI再次渲染的速度。。如下圖(沒加入主存時候)

分析B: 接著我們來看問題B。也許這時候你覺得程序已經不存在問題了,確實,現在的程序是不存在問題了,但是可能會遇到問題。就是遇到一種十分極端的情況,這種情況可以通過斷網來進行模擬。(模擬數據量過大,或者下載速度太慢,此時用戶不斷滾動TableView)會造成,因為圖片沒下載好,也就還沒緩存到主存,所以當要取圖片的時候,到主存對應的位置去取,卻發現沒有,這時候,就會調用網絡下載,下載圖片,就造成了不斷重復的下載。如下圖

解決B這時候我們就需要某種標志來,標志該下載已經存在,不需要重新下載。所以我用了一個字典來映射各個下載圖片的操作,在下載操作執行前從字典中取出,判斷有沒有該操作,有則不重復下載。這是可以打開第52,和82行即可,觀察到效果。(記得打開網絡!)如下圖

分析C: 其實C問題所起來很好解決,閱讀我的源代碼,你可以看到第75行是在當前線程中寫入數據到磁盤,這就造成了,要等待該寫入操作完成后才退出該函數,接著才將渲染任務交給主線程。但是寫入操作和渲染操作其實是可以同時進行的。所以我們可以在這里使用異步函數

解決C:打開對應的注釋(72和77), 驗證就不在做了,可以自己打印時間觀察。

所以對于多圖片下載的問題我們主要是這么做:1.通過多線程的方式,解決UI能流暢渲染,。2.通過利用內存構架提高UI渲染的速度,并且解決了第一種圖片重復下載問題。3.通過標記操作,實現同一下載互斥,解決UITableViewCell重用機制造成的第二種圖片重復下載問題。

具體判斷邏輯與細節:

1.先判斷主存緩存中有沒有圖片,如果沒有進行第二步

2.判斷磁盤有沒有緩存的圖片,如果有則直接加載進主存緩存中,并記錄該次操作,如果沒有進行第三步。

3.先判斷該下載操作是否存在,如果存在,則不進行下載操作。如果不存在進行第四步。

4.從網絡中下載圖片,并且判斷下載是否成功,如果成功下載,則記錄該次下載操作,實現互斥。再將圖片寫入主存緩存,并開啟另外一個線程將圖片寫入磁盤。

如果沒有下載成功或者從磁盤中沒有加載成功,則移除該次的下載標志, 解除該次下載互斥。


5.主線程直接從主存中的圖片緩存位置來圖片,渲染到UI界面。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 上犹县| 五常市| 凯里市| 藁城市| 巨鹿县| 五指山市| 齐河县| 互助| 庆云县| 潍坊市| 喀喇| 杨浦区| 吉首市| 九龙县| 花莲县| 冷水江市| 天台县| 藁城市| 龙海市| 临汾市| 兰坪| 大宁县| 深州市| 泾源县| 丰顺县| 元江| 博乐市| 乐陵市| 荆州市| 平顺县| 伊春市| 惠安县| 建宁县| 巴林左旗| 临猗县| 宁海县| 江北区| 万全县| 泌阳县| 永寿县| 元氏县|