Kingfisher使用備忘錄

簡(jiǎn)單使用

let url = URL(string: "https://domain.com/image.jpg")!
imageView.kf.setImage(with: url)

傳入url即可。Kingfisher會(huì)嘗試從緩存中獲取圖像,如果找不到,才回去下載,然后緩存使用。緩存的key是url的absoluteString。

指定緩存鍵

let resource = ImageResource(downloadURL: url, cacheKey: "my_cache_key")
imageView.kf.setImage(with: resource)

如果想自定義緩存key,可以這樣做。

使用占位圖像

let image = UIImage(named: "default_profile_icon")
imageView.kf.setImage(with: url, placeholder: image)

可以自定義占位圖像。當(dāng)然,也可以自定義UIView為占位視圖,只需要該視圖遵循Placeholder即可。

class MyView: UIView { /* Your implementation of view */ }

extension MyView: Placeholder { /* Just leave it empty */}

imageView.kf.setImage(with: url, placeholder: MyView())

使用完成后的閉包

imageView.kf.setImage(with: url, completionHandler: { 
(image, error, cacheType, imageUrl) in
// image: Image? `nil` means failed
// error: NSError? non-`nil` means failed
// cacheType: CacheType
//                  .none - Just downloaded
//                  .memory - Got from memory cache
//                  .disk - Got from disk cache
// imageUrl: URL of the image
})

下載完成或者發(fā)生錯(cuò)誤后,會(huì)調(diào)用該閉包。

下載時(shí)帶有指示器

imageView.kf.indicatorType = .activity
imageView.kf.setImage(with: url)

會(huì)帶有下載指示器

下載時(shí)使用自定義的GIF文件或者任何圖像作為指示圖像

let p = Bundle.main.path(forResource: "loader", ofType: "gif")!
let data = try! Data(contentsOf: URL(fileURLWithPath: p))

imageView.kf.indicatorType = .image(imageData: data)

imageView.kf.setImage(with: url)

使用自定義視圖指示

struct MyIndicator: Indicator {
let view: UIView = UIView()

func startAnimatingView() { view.isHidden = false }
func stopAnimatingView() { view.isHidden = true }

init() {
view.backgroundColor = .red
}
}

let i = MyIndicator()
imageView.kf.indicatorType = .custom(indicator: i)

使用進(jìn)度模塊更新自己的指示UI

imageView.kf.setImage(with: url, progressBlock: {
receivedSize, totalSize in
let percentage = (Float(receivedSize) / Float(totalSize)) * 100.0
print("downloading progress: \(percentage)%")
myIndicator.percentage = percentage
})

下載后設(shè)置圖像時(shí)添加淡入淡出過(guò)渡

imageView.kf.setImage(with: url, options: [.transition(.fade(0.2))])

在顯示和緩存前將下載的圖像轉(zhuǎn)換成圓角

let processor = RoundCornerImageProcessor(cornerRadius: 20)
imageView.kf.setImage(with: url, placeholder: nil, options: [.processor(processor)])

可以定義成其他效果,比如模糊,色調(diào),黑白等

設(shè)置圖像之前應(yīng)用多個(gè)處理

let processor = BlurImageProcessor(blurRadius: 4) >> RoundCornerImageProcessor(cornerRadius: 20)
imageView.kf.setImage(with: url, placeholder: nil, options: [.processor(processor)])

跳過(guò)緩存搜索,強(qiáng)制下載圖像

imageView.kf.setImage(with: url, options: [.forceRefresh])

只搜索緩存中的圖片,不存在也不下載

imageView.kf.setImage(with: url, options: [.onlyFromCache])

應(yīng)用在UIButton和NSButton上時(shí)

let uiButton: UIButton = //...
uiButton.kf.setImage(with: url, for: .normal, placeholder: nil, options: nil, progressBlock: nil, completionHandler: nil)
uiButton.kf.setBackgroundImage(with: url, for: .normal, placeholder: nil, options: nil, progressBlock: nil, completionHandler: nil)

let nsButton: NSButton = //...
nsButton.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: nil, completionHandler: nil)
nsButton.kf.setAlternateImage(with: url, placeholder: nil, options: nil, progressBlock: nil, completionHandler: nil)

緩存和下載器

Kingfisher由兩個(gè)主要組件組成:一個(gè)ImageDownloader用于下載圖像,一個(gè)ImageCache用于處理緩存。你可以單獨(dú)使用它們中的任何一個(gè)。

使用ImageDownloader下載的圖像沒(méi)有被緩存

ImageDownloader.default.downloadImage(with: url, options: [], progressBlock: nil) {
(image, error, url, data) in
print("Downloaded Image: \(image)")
}

使用ImageCache存儲(chǔ)或獲取圖像

let image: UIImage = //...
ImageCache.default.store(image, forKey: "key_for_image")

let anotherImage: UIImage = //...
let imageData = //.. Data from anotherImage
ImageCache.default.store(anotherImage, 
original: imageData, 
forKey: "key_for_another_image", 
toDisk: false)

ImageCache.default.isImageCached(forKey: "key_for_image")
// (cached: true, cacheType: .memory)
ImageCache.default.isImageCached(forKey: "key_for_another_image")
// (cached: true, cacheType: .memory)

// Force quit and relaunch
ImageCache.default.isImageCached(forKey: "key_for_image")
// (cached: true, cacheType: .disk)
ImageCache.default.isImageCached(forKey: "key_for_another_image")
// (cached: false, cacheType: .none)

ImageCache.default.retrieveImage(forKey: "key_for_image", options: nil) { 
image, cacheType in
if let image = image {
print("Get image \(image), cacheType: \(cacheType).")
//In this code snippet, the `cacheType` is .disk
} else {
print("Not exist in cache.")
}
}

刪除緩存圖像

// From both memory and disk
ImageCache.default.removeImage(forKey: "key_for_image")

// Only from memory
ImageCache.default.removeImage(forKey: "key_for_image", fromDisk: false)

設(shè)置緩存磁盤大小

// 50 MB
ImageCache.default.maxDiskCacheSize = 50 * 1024 * 1024
// Default value is 0, which means no limit.

默認(rèn)使用default

獲取已用磁盤大小

ImageCache.default.calculateDiskCacheSize { size in
print("Used disk size by bytes: \(size)")
}

手動(dòng)清除緩存

// Clear memory cache right away.
cache.clearMemoryCache()

// Clear disk cache. This is an async operation.
cache.clearDiskCache()

// Clean expired or size exceeded disk cache. This is an async operation.
cache.cleanExpiredDiskCache()

收到內(nèi)存警告時(shí),會(huì)清除內(nèi)存中的緩存,并且清理過(guò)期的和超出尺寸的緩存,通常不需要手動(dòng)清理。

設(shè)置緩存保持時(shí)間

// 3 days
ImageCache.default.maxCachePeriodInSecond = 60 * 60 * 24 * 3
// Default value is 60 * 60 * 24 * 7, which means 1 week.

設(shè)置-1表示永不過(guò)期

為緩存文件添加后綴

// Set a default path extension
KingfisherManager.shared.cache.pathExtension = "jpg"

為圖片下載器設(shè)置超時(shí)時(shí)間

// 30 second
ImageDownloader.default.downloadTimeout = 30.0
// Default value is 15.

使用自定義的下載器和緩存

let downloader = ImageDownloader(name: "huge_image_downloader")
downloader.downloadTimeout = 150.0
let cache = ImageCache(name: "longer_cache")
cache.maxDiskCacheSize = 60 * 60 * 24 * 30

imageView.kf.setImage(with: url, options: [.downloader(downloader), .targetCache(cache)])

取消下載或者重新下載

// In table view data source
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//...
cell.imageView.kf.setImage(with: url)
//...
}

// In table view delegate
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
//...
cell.imageView.kf.cancelDownloadTask()
}

發(fā)送前修改請(qǐng)求

let modifier = AnyModifier { request in
var r = request
r.setValue("", forHTTPHeaderField: "Access-Token")
return r
}       
imageView.kf.setImage(with: url, placeholder: nil, options: [.requestModifier(modifier)])

身份驗(yàn)證NSURLCredential

// In ViewController
ImageDownloader.default.authenticationChallengeResponder = self

extension ViewController: AuthenticationChallengeResponsable {
func downloader(_ downloader: ImageDownloader,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
{
// Provide your `AuthChallengeDisposition` and `URLCredential`
let disposition: URLSession.AuthChallengeDisposition = // ..
let credential: URLCredential? = //..
completionHandler(disposition, credential)
}
}

檢查HTTP狀態(tài)碼確認(rèn)是否有效

// In ViewController
ImageDownloader.default.delegate = self

extension ViewController: ImageDownloaderDelegate {
func isValidStatusCode(_ code: Int, for downloader: ImageDownloader) -> Bool {
return code == 200 || code == 202
}
}

在下載器中使用自己的會(huì)話配置

let imageDownloader: ImageDownloader = //...

// A configuration without persistent storage for caches is 
// requsted for downloader working correctly. (Based on `URLSessionConfiguration.ephemeral`)
imageDownloader.sessionConfiguration = //...

處理器

ImageProcessor更像是圖像的變形。它將一些數(shù)據(jù)轉(zhuǎn)換為圖像或圖像。你可以提供一個(gè)處理器ImageDownloader。下載器會(huì)將其應(yīng)用于下載的數(shù)據(jù)/圖像,然后在需要時(shí)將處理后的圖像發(fā)送到圖像視圖或緩存。

使用默認(rèn)處理器

// Just without anything
imageView.kf.setImage(with: url)
// It equals to
imageView.kf.setImage(with: url, options: [.processor(DefaultImageProcessor.default)])

默認(rèn)處理器將下載的數(shù)據(jù)轉(zhuǎn)換為相應(yīng)的圖像對(duì)象,PNG,JPEG和GIF都支持。

內(nèi)置處理器

// Round corner
let processor = RoundCornerImageProcessor(cornerRadius: 20)

// Resizing
let processor = ResizingImageProcessor(referenceSize: CGSize(width: 100, height: 100))

// Cropping
let processor = CroppingImageProcessor(size: CGSize(width: 100, height: 100), anchor: CGPoint(x: 0.5, y: 0.5))

// Blur with a radius
let processor = BlurImageProcessor(blurRadius: 5.0)

// Overlay with a color & fraction
let processor = OverlayImageProcessor(overlay: .red, fraction: 0.7)

// Tint with a color
let processor = TintImageProcessor(tint: .blue)

// Adjust color
let processor = ColorControlsProcessor(brightness: 1.0, contrast: 0.7, saturation: 1.1, inputEV: 0.7)

// Black & White
let processor = BlackWhiteProcessor()

// Blend (iOS)
let processor = BlendImageProcessor(blendMode: .darken, alpha: 1.0, backgroundColor: .lightGray)

// Compositing
let processor = CompositingImageProcessor(compositingOperation: .darken, alpha: 1.0, backgroundColor: .lightGray)

imageView.kf.setImage(with: url, options: [.processor(processor)])

連接處理器

// Blur and then make round corner
let processor = BlurImageProcessor(blurRadius: 5.0) >> RoundCornerImageProcessor(cornerRadius: 20)
imageView.kf.setImage(with: url, options: [.processor(processor)])

// `>>` equals the `append(another:)` method of `ImageProcessor`.
// Above equals to:
let processor = BlurImageProcessor(blurRadius: 5.0).append(RoundCornerImageProcessor(cornerRadius: 20))

創(chuàng)建并使用自己的處理器

struct WebpProcessor: ImageProcessor {
// `identifier` should be the same for processors with same properties/functionality
// It will be used when storing and retrieving the image to/from cache.
let identifier = "com.yourdomain.webpprocessor"

// Convert input data/image to target image and return it.
func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
switch item {
case .image(let image):
print("already an image")
return image
case .data(let data):
return WebpFramework.createImage(from: webpData)
}
}
}

// Then pass it to the `setImage` methods:
let processor = WebpProcessor()
let url = URL(string: "https://yourdomain.com/example.webp")
imageView.kf.setImage(with: url, options: [.processor(processor)])

創(chuàng)建過(guò)濾

struct MyCIFilter: CIImageProcessor {

let identifier = "com.yourdomain.myCIFilter"

let filter = Filter { input in
guard let filter = CIFilter(name: "xxx") else { return nil }
filter.setValue(input, forKey: kCIInputBackgroundImageKey)
return filter.outputImage
}
}

使用處理器緩存

let processor = WebpProcessor()
let url = URL(string: "https://yourdomain.com/example.webp")
imageView.kf.setImage(with: url, options: [.processor(processor)])

// Later
ImageCache.default.isImageCached(
forKey: url.cacheKey, 
processorIdentifier: processor.identifier)

緩存原始圖像用于多個(gè)處理器處理

let p = MyProcessor()
imageView.kf.setImage(with: url, options: [.processor(p), .cacheOriginalImage])

使用序列化程序

// Just without anything
imageView.kf.setImage(with: url)
// It equals to
imageView.kf.setImage(with: url, options: [.cacheSerializer(DefaultCacheSerializer.default)])

指定緩存格式

let roundCorner = RoundCornerImageProcessor(cornerRadius: 20)
imageView.kf.setImage(with: url, 
options: [.processor(roundCorner), 
.cacheSerializer(FormatIndicatedCacheSerializer.png)]
)

創(chuàng)建自定義的序列化程序

struct WebpCacheSerializer: CacheSerializer {
func data(with image: Image, original: Data?) -> Data? {
return WebpFramework.webpData(of: image)
}

func image(with data: Data, options: KingfisherOptionsInfo?) -> Image? {
return WebpFramework.createImage(from: webpData)
}
}

// Then pass it to the `setImage` methods:
let serializer = WebpCacheSerializer()
let url = URL(string: "https://yourdomain.com/example.webp")
imageView.kf.setImage(with: url, options: [.cacheSerializer(serializer)])

預(yù)取

可以預(yù)先取出一些圖像將其緩存,然后顯示在屏幕上。

let urls = ["http://example.com/image1.jpg", "http://example.com/image2.jpg"]
.map { URL(string: $0)! }
let prefetcher = ImagePrefetcher(urls: urls) {
skippedResources, failedResources, completedResources in
print("These resources are prefetched: \(completedResources)")
}
prefetcher.start()

// Later when you need to display these images:
imageView.kf.setImage(with: urls[0])
anotherImageView.kf.setImage(with: urls[1])

Prefetcher與UICollectionView或UITableView一起使用

override func viewDidLoad() {
super.viewDidLoad()
collectionView?.prefetchDataSource = self
}

extension ViewController: UICollectionViewDataSourcePrefetching {
func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) {
let urls = indexPaths.flatMap { URL(string: $0.urlString) }
ImagePrefetcher(urls: urls).start()
}
}

動(dòng)畫GIF

let imageView: UIImageView = ...
imageView.kf.setImage(with: URL(string: "your_animated_gif_image_url")!)

如果在處理大型GIF時(shí)遇到內(nèi)存問(wèn)題,請(qǐng)嘗試使用AnimatedImageView而不是常規(guī)圖像視圖來(lái)顯示GIF。它只會(huì)解碼您的GIF圖像的幾個(gè)幀,以獲得更小的內(nèi)存占用(但CPU負(fù)載很高)。

let imageView = AnimatedImageView()
imageView.kf.setImage(with: URL(string: "your_large_animated_gif_image_url")!)

只加載來(lái)自GIF的第一幀

imageView.kf.setImage(with: URL(string: "your_animated_gif_image_url")!, 
options: [.onlyLoadFirstFrame])

圖片擴(kuò)展

可以使用處理器/過(guò)濾器來(lái)單獨(dú)處理圖像。

extension Image {
public func kf.image(withRoundRadius radius: CGFloat, fit size: CGSize, scale: CGFloat) -> Image { }
public func kf.resize(to size: CGSize) -> Image { }
public func kf.blurred(withRadius radius: CGFloat) -> Image { }
public func kf.overlaying(with color: Color, fraction: CGFloat) -> Image { }
public func kf.tinted(with color: Color) -> Image { }
public func kf.adjusted(brightness: CGFloat, contrast: CGFloat, saturation: CGFloat, inputEV: CGFloat) -> Image { }
public func kf.apply(_ filter: Filter) -> Image { }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,405評(píng)論 4 61
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 30,246評(píng)論 8 265
  • 20170116 今天終于做上大排畸B超了。呵呵,以前一聽這個(gè)名字,總有種大雞排的錯(cuò)覺。 關(guān)于這個(gè)檢查,我聽周邊很...
    蕭蕭依舊閱讀 418評(píng)論 0 0
  • github老地址:https://github.com/MaxwellQi github新地址: https:/...
    iosmedia閱讀 272評(píng)論 0 0
  • 男盜女娼你吵吵鬧鬧才能粉嫩小糯米想念想念 你的蜜蜂們出門 vv 媽媽 v
    小飛飛啦閱讀 286評(píng)論 0 0

友情鏈接更多精彩內(nèi)容