2017-06-16 46 views
2

關於如何異步加載圖像和其他下載的數據有很多疑問,但沒有關於將這些圖像異步加載到UI中的問題。異步加載所有單元格內容

我想在我的UICollectionView上實現60 fps滾動,雖然我正在尋找適用於所有視圖的解決方案。

例如,如果我的資產文件夾中有要加載到快速滾動的UIScrollView中的圖像,則需要花費時間將它們帶入內存,然後在用戶界面中繪製。有什麼辦法可以先將這些圖像緩存在內存中(雖然不會傷害內存/使用太多),然後一旦將它們緩存到內存中,就將它們加載到內存中?

正如我現在明白了,當我說,

cell.imageView.image = UIImage(named: "grapes") 

資產文件夾grapes打開和讀取,然後它帶來相應的圖像(1X,2X,3X或)到內存中。將正確的圖像存入內存後,將cell.imageView.image分配給它,然後繪製圖像。這是否準確?所有這些都發生在主線程上嗎?如果是這樣,那麼這是不是有可能阻塞主線程並導致設備跳過一些幀?

我假設在求解複雜表達式或格式化文本時會發生類似的過程。如果是這樣,那麼可以以及如何創建要異步加載的內容,以便主線程不會被阻塞(即使以臨時爲空的內容視圖爲代價)?

+0

@Rob,通過「圖像的大小不適合用戶界面」,你的意思是UIImageView需要執行更多的操作來縮放或其他東西? – IHaveAQuestion

+0

我在說的是一個圖像視圖,也就是說40x40點,但是您使用的圖像是1200x1200像素,並且您使用了「.scaleAspectFit」或「.scaleAspectFill」的內容模式。真的是任何情況下,你依靠'contentMode'來適當縮放你的圖像。或者,顯然,如果你正在調用你自己的縮放/裁剪例程。 – Rob

回答

0

創建的背景圖片,在UI線程設置:

DispatchQueue.global(qos: .background).async { 
    let image = UIImage(named: "image") 

    DispatchQueue.main.async { 
     cell.imageView.image = image 
    } 
} 

這是簡化的例子,你需要花費大約滾動和細胞回用護理。

+0

我認爲所有改變用戶界面的東西都需要在主線程上發生? – IHaveAQuestion

+0

@IHaveAQuestion這不是一個用戶界面,你不應該改變後臺線程的UI樹視圖,但你可以加載任何你想要的 –

+0

真棒,謝謝!另外,爲什麼你把所有的東西放在那個塊裏面?也就是'.global(qos:.background).async'和'.main.async'有什麼區別? – IHaveAQuestion

1

是的,加載和映像到內存可能需要幾毫秒。如果圖片尺寸不適合用戶界面(例如,您正在依靠contentMode類似scaleAspectFit.scaleAspectFill將圖片大小適當;或者如果您自己手動調整大小/裁剪圖片),它尤其會影響體驗。這可能會導致一些令人驚訝的計算複雜的東西。

通常,這是不夠的是有問題,但它可以防止你實現最佳的60 fps。如果您想要獲得最佳性能,您可以進行異步檢索,將其與table view prefetchingcollection view prefetching相結合。

重複複雜的表達式和文本格式,這不太可能引入足夠的延遲來防止60 fps。但不要猜測(重新這個或圖像)。您應該通過儀器分析「發佈」版本的fps(打開優化),並查看其中哪些(如果其中之一)對fps具有可觀察的影響。並測試你的目標物理設備,而不是模擬器,因爲如果過早地浪費時間來優化物理設備上不會發生的問題,那將是一件恥辱。

+0

單元格中的簡單UIView動畫是否會減慢幀頻? – IHaveAQuestion

+0

我建議你不要猜測什麼可能會影響fps,並憑經驗驗證(通過優化版本構建)實際做了什麼。 「不成熟的優化是萬惡之源,但我們不應該在這個關鍵的3%中放棄我們的機會。」在你失去太多的睡眠之前,請確保你在這3%。但是,在回答你的問題時,不,簡單的動畫可能不會對fps產生不利影響,儘管複雜的動畫(例如使用高斯模糊/陰影的複雜視圖動畫可能更好)。 – Rob