版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2020.10.09 星期五 |
前言
在我們開發(fā)中總有從遠(yuǎn)程下載圖片帖族,OC中有個很成熟的三方框架甚垦,大家都知道的
SDWebImage
艰亮,同樣Swift中也有類似的三方框架Nuke
迄埃,接下來幾篇我們就一起看一下這個框架侄非。
開始
首先我們看一下該項目的GitHub地址 Nuke者疤。
Nuke提供了一種簡單有效的方法來下載和顯示應(yīng)用程序中的圖像驹马。 簡潔明了的API背后是先進(jìn)的體系結(jié)構(gòu)糯累,該體系結(jié)構(gòu)具有其獨(dú)特的功能并提供了幾乎無限的自定義可能性。 Nuke的主要功能是性能 - performance。
Fast LRU memory and disk cache · SwiftUI · Smart background decompression · Image processing · Elegant builder API · Resumable downloads · Intelligent deduplication · Request prioritization · Low data mode · Prefetching · Rate limiting · Progressive JPEG, HEIF, WebP, SVG, GIF · Alamofire · Combine · Reactive extensions
Nuke
易于學(xué)習(xí)和使用借笙。 以下是其API和功能的概述:
-
Image View Extensions - UI Extensions · Table View · Placeholders, Transitions ·
ImageRequest
-
Image Processing -
Resize
·Circle
·RoundedCorners
·GaussianBlur
·CoreImage
· Custom Processors -
Image Pipeline - Load Image ·
ImageTask
· Customize Image Pipeline · Default Pipeline - Caching - LRU Memory Cache · HTTP Disk Cache · Aggressive LRU Disk Cache
- Advanced Features - Preheat Images · Progressive Decoding
- Extensions ? FetchImage · Builder · Combine · RxNuke · And More
要了解更多信息,請參閱完整的API Reference,并查看存儲庫中包含的演示項目熔号。 準(zhǔn)備安裝時引镊,請遵循Installation Guide弟头。 請參閱Requirements赴恨,以獲取受支持平臺的列表雨饺。 如果遇到任何問題沛膳,請參閱FAQ或Troubleshooting Guide锹安。
要了解有關(guān)管道和支持的格式的更多信息,請參見專用指南风罩。
- Image Formats ? Progressive JPEG · HEIF · GIF · SVG · WebP
- Image Pipeline ? Data Loading · Resumable Downloads · Memory Cache · Deduplication · Decompression · Performance
Image View Extensions
用單行代碼下載并在image view
中顯示圖像:
Nuke.loadImage(with: url, into: imageView)
Nuke
將檢查圖像是否在內(nèi)存緩存中舵稠,如果存在超升,將立即顯示它。 否則哺徊,圖像數(shù)據(jù)將在后臺加載室琢,解碼,處理和解壓縮
請參閱 Image Pipeline Guide以了解如何下載和處理圖像落追。
1. In a Table View
當(dāng)您為現(xiàn)有視圖請求新圖像時,Nuke
會為重用做好準(zhǔn)備轿钠,并取消對該視圖的所有未完成請求巢钓。
func tableView(_ tableView: UITableView, cellForItemAt indexPath: IndexPaths) -> UITableViewCell {
/* Create a cell ... */
Nuke.loadImage(with: url, into: cell.imageView)
}
視圖
deallocated
后,關(guān)聯(lián)的請求將自動取消疗垛。 要手動取消請求症汹,請調(diào)用Nuke.cancelRequest(for:imageView)
。
2. Placeholders, Transitions, Content Modes, Tint Colors
使用ImageLoadingOptions
設(shè)置一個placeholder
继谚,選擇一個內(nèi)置transitions
烈菌,或提供一個自定義過渡阵幸。
let options = ImageLoadingOptions(
placeholder: UIImage(named: "placeholder"),
transition: .fadeIn(duration: 0.33)
)
Nuke.loadImage(with: url, options: options, into: imageView)
您甚至可以自定義content mode
或每種圖像類型的tint color
:
let options = ImageLoadingOptions(
placeholder: UIImage(named: "placeholder"),
failureImage: UIImage(named: "failureImage"),
contentModes: .init(success: .scaleAspectFill, failure: .center, placeholder: .center),
tintColors: .init(success: .green, failure: .red, placeholder: .yellow)
)
如果希望所有圖像視圖都具有相同的行為,則可以修改
ImageLoadingOptions.shared
芽世。
請記住挚赊,圖像視圖的內(nèi)置擴(kuò)展程序旨在使您盡快啟動并運(yùn)行。 如果您想擁有更多控制權(quán)或使用某些高級功能(例如動畫圖像)济瓢,建議直接在自定義視圖中使用ImagePipeline
荠割。
3. ImageRequest
ImageRequest
允許您設(shè)置圖像處理器,更改請求優(yōu)先級等:
let request = ImageRequest(
url: URL(string: "http://..."),
processors: [ImageProcessors.Resize(size: imageView.bounds.size)],
priority: .high
)
應(yīng)用處理器的另一種方法是在
ImagePipeline.Configuration
上設(shè)置默認(rèn)processors
旺矾。 這些處理器將應(yīng)用于管道加載的所有圖像蔑鹦。 如果請求中包含非空的處理器數(shù)組,則將應(yīng)用它們箕宙。
可通過ImageRequestOptions
使用的高級選項嚎朽。 例如,如果URL
包含瞬態(tài)查詢參數(shù)柬帕,則可以提供一個filteredURL
用作緩存的鍵哟忍。
let request = ImageRequest(
url: URL(string: "http://example.com/image.jpeg?token=123")!,
options: ImageRequestOptions(
filteredURL: "http://example.com/image.jpeg"
)
)
有更多選項可用,要查看所有選項陷寝,請查看內(nèi)聯(lián)文檔以了解ImageRequestOptions
锅很。
Image Processing
Nuke
具有強(qiáng)大而高效的圖像處理基礎(chǔ)架構(gòu),具有多個內(nèi)置處理器凤跑,您可以在ImageProcessors
命名空間中找到它們爆安,例如 ImageProcessors.Resize
。
此截圖和其他屏幕截圖來自倉庫中包含的演示項目仔引。
1. Resize
要調(diào)整圖像大小扔仓,請使用ImageProcessors.Resize
:
ImageRequest(url: url, processors: [
ImageProcessors.Resize(size: imageView.bounds.size)
])
默認(rèn)情況下,target size
以點(diǎn)為單位咖耘。 加載圖像后当辐,Nuke
將縮小圖像以填充目標(biāo)區(qū)域,并保持寬高比鲤看。 要裁切圖像,請將crop
設(shè)置為true
耍群。 有關(guān)更多選項义桂,請參見ImageProcessors.Resize
文檔。
使用可選的Builder軟件包獲得更簡潔的API蹈垢。
pipeline.image(with: URL(string: "https://")!) .resize(width: 320) .blur(radius: 10)
2. Circle
將圖像的角圓成帶有可選邊框的圓慷吊。
ImageRequest(url: url, processors: [
ImageProcessors.Circle()
])
3. RoundedCorners
將圖像的角圓整到指定的半徑。 確保調(diào)整圖像大小以與顯示圖像的視圖大小完全匹配曹抬,以便正確顯示邊框溉瓶。
ImageRequest(url: url, processors: [
ImageProcessors.Circle(radius: 16)
])
4. GaussianBlur
ImageProcessors.GaussianBlur
使用Core Image濾鏡之一模糊輸入圖像。
5. CoreImageFilter
使用ImageProcessors.CoreImageFilter
應(yīng)用大量的Core Image filters:
ImageProcessors.CoreImageFilter(name: "CISepiaTone")
6. Custom Processors
對于簡單的一次性操作,請使用ImageProcessors.Anonymous
創(chuàng)建帶閉包的處理器堰酿。
定制處理器需要實(shí)現(xiàn)ImageProcessing
協(xié)議疾宏。 為了滿足基本的圖像處理需求,請實(shí)現(xiàn)process(_ :)
方法并創(chuàng)建一個唯一標(biāo)識處理器的標(biāo)識符触创。 對于沒有輸入?yún)?shù)的處理器坎藐,您可以返回靜態(tài)字符串。
public protocol ImageProcessing {
func process(image: UIImage) -> UIImage? // NSImage on macOS
var identifier: String // get
}
如果您的處理器需要操縱圖像元數(shù)據(jù)(ImageContainer)
哼绑,或者需要通過ImageProcessingContext
訪問更多信息岩馍,那么除了process(_ :)
之外,您還可以實(shí)現(xiàn)其他方法抖韩。
public protocol ImageProcessing {
func process(_ image container: ImageContainer, context: ImageProcessingContext) -> ImageContainer?
}
除了var identfier:String
外蛀恩,您還可以實(shí)現(xiàn)var hashableIdentifier:AnyHashable
,以供內(nèi)存高速緩存使用茂浮,因?yàn)樵谶@種情況下双谆,字符串操作太慢。 默認(rèn)情況下励稳,此方法返回identifier
字符串佃乘。 一種常見的方法是使處理器可Hashable
,并從hashableIdentifier
返回self
驹尼。
Image Pipeline
Nuke
的核心是ImagePipeline
類趣避。 直接使用管道來加載圖像而不顯示它們:
let task = ImagePipeline.shared.loadImage(
with: url,
progress: { _, completed, total in
print("progress updated")
},
completion: { result: Result<ImageResponse, ImagePipeline.Error> in
print("task completed")
}
)
loadImage
返回值始終異步調(diào)用完成閉包。 若要檢查圖像是否存儲在內(nèi)存緩存中新翎,請使用pipeline.cachedImage(for:url)
程帕。
要下載數(shù)據(jù)而不進(jìn)行任何昂貴的解碼或處理,請使用
loadData(with:progress:completion :)
地啰。
1. ImageTask
啟動請求時愁拭,管道將返回ImageTask
對象,該對象可用于取消操作以及更多操作亏吝。
task.cancel()
task.priority = .high
2. Customize Image Pipeline
如果您想構(gòu)建一個適合您特定需求的系統(tǒng)岭埠,那么您將不會失望。 有很多事情需要調(diào)整蔚鸥。 您可以設(shè)置自定義數(shù)據(jù)加載器和緩存惜论,配置圖像編碼器和解碼器,更改每個單獨(dú)階段的并發(fā)操作數(shù)止喷,禁用和啟用重復(fù)數(shù)據(jù)刪除和速率限制等功能馆类。
要了解更多信息,請參見
ImagePipeline.Configuration
和Image Pipeline Guide的內(nèi)聯(lián)文檔弹谁。
以下是可用于自定義的協(xié)議:
-
DataLoading
–下載(或返回緩存的)圖像數(shù)據(jù) -
DataCaching
–將圖像數(shù)據(jù)存儲在磁盤上 -
ImageDecoding
–將數(shù)據(jù)轉(zhuǎn)換為圖像(有關(guān)新的實(shí)驗(yàn)性解碼功能乾巧,請參見_ImageDecoding
) -
ImageEncoding
-將圖像轉(zhuǎn)換為數(shù)據(jù) -
ImageProcessing
–應(yīng)用圖像轉(zhuǎn)換 -
ImageCaching
–將圖像存儲到內(nèi)存緩存中
整個配置由ImagePipeline.Configuration
結(jié)構(gòu)描述句喜。 要使用自定義配置創(chuàng)建管道,請調(diào)用ImagePipeline(configuration :)
初始值設(shè)定項或使用便捷的一種:
let pipeline = ImagePipeline {
$0.dataLoader = ...
$0.dataLoadingQueue = ...
$0.imageCache = ...
...
}
然后將新管道設(shè)置為默認(rèn)值:
ImagePipeline.shared = pipeline
3. Default Image Pipeline
默認(rèn)圖像管道使用以下依賴項(dependencies)
進(jìn)行初始化:
// Shared image cache with a size limit of ~20% of available RAM.
imageCache = ImageCache.shared
// Data loader with a default `URLSessionConfiguration` and a custom `URLCache`
// with memory capacity 0, and disk capacity 150 MB.
dataLoader = DataLoader()
// Custom aggressive disk cache is disabled by default.
dataCache = nil
// By default uses the decoder from the global registry and the default encoder.
makeImageDecoder = ImageDecoderRegistry.shared.decoder(for:)
makeImageEncoder = { _ in ImageEncoders.Default() }
管道中的每個操作都在專用隊列上運(yùn)行:
dataLoadingQueue.maxConcurrentOperationCount = 6
dataCachingQueue.maxConcurrentOperationCount = 2
imageDecodingQueue.maxConcurrentOperationCount = 1
imageEncodingQueue.maxConcurrentOperationCount = 1
imageProcessingQueue.maxConcurrentOperationCount = 2
imageDecompressingQueue.maxConcurrentOperationCount = 2
您可以調(diào)整以下管道設(shè)置列表:
// Automatically decompress images in the background by default.
isDecompressionEnabled = true
// Configure what content to store in the custom disk cache.
dataCacheOptions.storedItems = [.finalImage] // [.originalImageData]
// Avoid doing any duplicated work when loading or processing images.
isDeduplicationEnabled = true
// Rate limit the requests to prevent trashing of the subsystems.
isRateLimiterEnabled = true
// Progressive decoding is an opt-in feature because it is resource intensive.
isProgressiveDecodingEnabled = false
// Don't store progressive previews in memory cache.
isStoringPreviewsInMemoryCache = false
// If the data task is terminated (either because of a failure or a
// cancellation) and the image was partially loaded, the next load will
// resume where it was left off.
isResumableDataEnabled = true
在所有管道之間共享一些全局選項:
// Enable to start using `os_signpost` to monitor the pipeline
// performance using Instruments.
ImagePipeline.Configuration.isSignpostLoggingEnabled = false
Caching
1. LRU Memory Cache
Nuke
的默認(rèn)ImagePipeline
具有兩個緩存層沟于。
首先咳胃,有一個內(nèi)存緩存,用于存儲準(zhǔn)備顯示的已處理圖像社裆。
// Configure cache
ImageCache.shared.costLimit = 1024 * 1024 * 100 // 100 MB
ImageCache.shared.countLimit = 100
ImageCache.shared.ttl = 120 // Invalidate image after 120 sec
// Read and write images
let request = ImageRequest(url: url)
ImageCache.shared[request] = ImageContainer(image: image)
let image = ImageCache.shared[request]
// Clear cache
ImageCache.shared.removeAll()
ImageCache
使用LRU算法-在掃描期間拙绊,首先刪除最近最少使用的條目。
2. HTTP Disk Cache
未處理的圖像數(shù)據(jù)存儲在URLCache
中泳秀。
// Configure cache
DataLoader.sharedUrlCache.diskCapacity = 100
DataLoader.sharedUrlCache.memoryCapacity = 0
// Read and write responses
let request = ImageRequest(url: url)
let _ = DataLoader.sharedUrlCache.cachedResponse(for: request.urlRequest)
DataLoader.sharedUrlCache.removeCachedResponse(for: request.urlRequest)
// Clear cache
DataLoader.sharedUrlCache.removeAllCachedResponses()
3. Aggressive LRU Disk Cache
如果您不愿意使用HTTP
緩存标沪,則可以嘗試使用自定義LRU
磁盤緩存進(jìn)行快速可靠的主動數(shù)據(jù)緩存(忽略 HTTP cache control)。 您可以使用管道配置啟用它嗜傅。
ImagePipeline {
$0.dataCache = try? DataCache(name: "com.myapp.datacache")
// Also consider disabling the native HTTP cache, see `DataLoader`.
}
默認(rèn)情況下金句,管道僅存儲原始圖像數(shù)據(jù)。 要存儲已下載和已處理的圖像吕嘀,請將dataCacheOptions.storedItems
設(shè)置為[.finalImage]
违寞。 如果您要存儲已處理的內(nèi)容,例如下采樣的圖像偶房,或者如果您想將圖像轉(zhuǎn)碼為更有效的格式趁曼,例如HEIF
。
要節(jié)省磁盤空間棕洋,請參閱
HEIF
支持的ImageEncoders.ImageIO
和ImageEncoder.isHEIFPreferred
選項挡闰。
Advanced Features
1. Image Preheating
預(yù)先預(yù)取圖像可以顯著改善應(yīng)用程序的用戶體驗(yàn)。
// Make sure to keep a strong reference to preheater.
let preheater = ImagePreheater()
preheater.startPreheating(with: urls)
// Cancels all of the preheating tasks created for the given requests.
preheater.stopPreheating(with: urls)
要了解有關(guān)您可以執(zhí)行的其他性能優(yōu)化的更多信息掰盘,請參見Performance Guide摄悯。
請記住,預(yù)取會占用用戶的數(shù)據(jù)愧捕,并給CPU和內(nèi)存帶來額外的壓力奢驯。 為了減少CPU和內(nèi)存的使用,您可以選擇僅選擇磁盤緩存作為預(yù)取目標(biāo):
// The preheater with `.diskCache` destination will skip image data decoding
// entirely to reduce CPU and memory usage. It will still load the image data
// and store it in disk caches to be used later.
let preheater = ImagePreheater(destination: .diskCache)
在iOS
上次绘,您可以將prefetching APIs與ImagePreheater
結(jié)合使用以自動執(zhí)行該過程瘪阁。
2. Progressive Decoding
要啟用漸進(jìn)式圖像解碼,請將isProgressiveDecodingEnabled
配置選項設(shè)置為true
邮偎。
let pipeline = ImagePipeline {
$0.isProgressiveDecodingEnabled = true
// If `true`, the pipeline will store all of the progressively generated previews
// in the memory cache. All of the previews have `isPreview` flag set to `true`.
$0.isStoringPreviewsInMemoryCache = true
}
就是這樣罗洗,管道將自動執(zhí)行正確的操作,并在進(jìn)度掃描到達(dá)時通過progress
閉包進(jìn)行漸進(jìn)式掃描:
let imageView = UIImageView()
let task = ImagePipeline.shared.loadImage(
with: url,
progress: { response, _, _ in
if let response = response {
imageView.image = response.image
}
},
completion: { result in
// Display the final image
}
)
Extensions
Nuke
有多種擴(kuò)展:
Name | Description |
---|---|
FetchImage | SwiftUI integration |
ImagePublisher | Combine publishers for Nuke |
ImageTaskBuilder | A fun and convenient way to use Nuke |
Alamofire Plugin | Replace networking layer with Alamofire and combine the power of both frameworks |
RxNuke | RxSwift extensions for Nuke with examples of common use cases solved by Rx |
WebP Plugin | [Community] WebP support, built by Ryo Kosuge |
Gifu Plugin | Use Gifu to load and display animated GIFs |
FLAnimatedImage Plugin | Use FLAnimatedImage to load and display animated GIFs |
Xamarin NuGet | [Community] Makes it possible to use Nuke from Xamarin |
1. FetchImage
FetchImage
是一個Swift
軟件包钢猛,可輕松使用Nuke
下載圖像并將其顯示在SwiftUI
應(yīng)用中。 有關(guān)更多信息轩缤,請參見introductory post命迈。
注意:這是一個
API
預(yù)覽贩绕,將來可能會更改。
public struct ImageView: View {
@ObservedObject var image: FetchImage
public var body: some View {
ZStack {
Rectangle().fill(Color.gray)
image.view?
.resizable()
.aspectRatio(contentMode: .fill)
}
}
}
2. Low Data Mode
FetchImage
還通過特殊的初始化程序?yàn)榈蛿?shù)據(jù)模式提供內(nèi)置支持:
FetchImage(regularUrl: highQualityUrl, lowDataUrl: lowQualityUrl)
3. Builder
覺得默認(rèn)的API有點(diǎn)無聊嗎壶愤? 試試ImageTaskBuilder淑倾,這是一種使用Nuke
的有趣且方便的方法。
ImagePipeline.shared.image(with: URL(string: "https://")!)
.fill(width: 320)
.blur(radius: 10)
.priority(.high)
.start { result in
print(result)
}
// Returns `ImageTask` when started.
let imageView: UIImageView
ImagePipeline.shared.image(with: URL(string: "https://")!)
.fill(width: imageView.size.width)
.display(in: imageView)
4. RxNuke
RxNuke為Nuke添加了RxSwift擴(kuò)展征椒,并啟用了常見用例:Going from low to high resolution | Loading the first available image | Showing stale image while validating it | Load multiple images, display all at once | Auto retry on failures | And more
要了解使用此擴(kuò)展程序可以做什么娇哆,請看一下先加載低分辨率圖像然后切換到高分辨率有多么容易:
let pipeline = ImagePipeline.shared
Observable.concat(pipeline.loadImage(with: lowResUrl).orEmpty,
pipeline.loadImage(with: highResUrl).orEmpty)
.subscribe(onNext: { imageView.image = $0 })
.disposed(by: disposeBag)
5. Combine
ImagePublisher為Nuke
添加了Combine
發(fā)行者,并且與RxNuke一樣勃救,啟用了各種功能強(qiáng)大的用例碍讨。
Contribution
Nuke's roadmap在Trello
中管理,并且可以公開獲得蒙秒。 如果您想貢獻(xiàn)勃黍,請隨時創(chuàng)建PR
。
1. Minimum Requirements
Nuke | Swift | Xcode | Platforms |
---|---|---|---|
Nuke 9.0 | Swift 5.1 | Xcode 11.0 | iOS 11.0 / watchOS 4.0 / macOS 10.13 / tvOS 11.0 |
Nuke 8.0 | Swift 5.0 | Xcode 10.2 | iOS 10.0 / watchOS 3.0 / macOS 10.12 / tvOS 10.0 |
有關(guān)舊版本的信息晕讲,請參見Installation Guide覆获。
后記
本篇主要講述了Swift中也有類似的三方框架
Nuke
,感興趣的給個贊或者關(guān)注~~~