簡(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 { }
}