麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 學院 > 開發(fā)設計 > 正文

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

2019-11-14 18:43:05
字體:
來源:轉載
供稿:網(wǎng)友

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

前言

下載地址, 后續(xù)發(fā)布, 請繼續(xù)關注本blog

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

內存結構

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

重點

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

判斷邏輯過程如下:

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

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

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

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

存在的問題:

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

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

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


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

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

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

- (void)setApp:(SWPApp *)app {        _app = app;        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{                // 1.子線程下載數(shù)據(jù)        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 磁盤無緩存則從網(wǎng)絡下載            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.先判斷下載該圖片的操作是否已經(jīng)執(zhí)行過    // 如果執(zhí)行過, 那么圖片緩存中必定存在圖片.   // if (!cache.OperationCache[self.app.icon]) {        static int i = 0;        NSLog(@"---%d", i);        data = isFilePath ? [NSData dataWithContentsOfFile: url]                          : (i++, [NSData dataWithContentsOfURL: [NSURL URLWithString: url ]]);                // 如果數(shù)據(jù)下載失敗        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界面的流暢度問題,我們就需要利用內存結構來節(jié)約用戶流量和提高UI再次渲染的速度。

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

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

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

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

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

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

具體判斷邏輯與細節(jié):

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

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

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

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

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


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


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: v片在线看 | 中国女警察一级毛片视频 | 欧美一级无毛 | 国产亚洲精品久久久久久久久久 | 国产精品区一区二区三区 | www.精品一区| 免费观看一区 | 久久精品欧美一区 | 国产色视频免费 | 日本不卡一二三区 | 日本特级a一片免费观看 | 欧美成人精品一区二区三区 | 色猫av | 狠狠干狠狠操 | 色交视频 | 国产色视频在线观看免费 | 欧美精品videos | 亚洲特黄| wankz100%videos| 美女视频黄视大全视频免费网址 | 国产成人精品区 | 成人不卡在线观看 | 新久草在线视频 | 九九精品在线播放 | 久久福利剧场 | 亚洲网站在线观看 | 亚洲一区二区免费 | 国产一级一级片 | 欧美性生话视频 | 欧洲成人在线视频 | 免费国产视频在线观看 | 亚洲欧美国产精品va在线观看 | gogo全球大胆高清人露出91 | 色屁屁xxxxⅹ在线视频 | av电影在线免费 | 91成人免费看片 | 黄色片在线播放 | 91久久极品少妇韩国 | 56av国产精品久久久久久久 | 久久久久久麻豆 | 久久精品中文字幕一区 |