Kingfisher的基本使用(一)

序言

Kingfisher 是一個下載撬码、緩存網(wǎng)絡(luò)圖片的輕量級純swift庫, 作者@王巍自稱是受著名三方庫SDWebImage激勵所寫版保,一年多以來呜笑,該庫深受廣大iOS之swift開發(fā)者所喜愛,目前被很多iOS開發(fā)者應(yīng)用在app中彻犁。在swift中它真的是一個SDWebImage的升級版叫胁,作為swift開發(fā)者來說,為了摒棄Objective-C的風(fēng)格汞幢,甚至“斷絕”與Objective-C的關(guān)系曹抬,使工程更swift化,我們更希望更喜歡使用純凈的swift來開發(fā)自己的app急鳄。在此,也非常感謝@喵神給眾多開發(fā)者提供了很大的便利堰酿,
為業(yè)界開發(fā)者所做的無私貢獻(xiàn)疾宏。

github: [Kingfisher] (https://github.com/onevcat/Kingfisher)

特征

  • 異步下載和緩存圖片
  • 基于networkingURLSession, 提供基礎(chǔ)的圖片處理器和過濾器
  • 內(nèi)存和磁盤的多層緩存
  • 可撤銷組件,可根據(jù)需要分開地使用下載器和緩存系統(tǒng)
  • 必要時可從緩存中讀取并展示圖片
  • 擴(kuò)展UIImageView触创、NSImage坎藐、UIButton來直接設(shè)置一個URL圖片
  • 設(shè)置圖片時,內(nèi)置過渡動畫
  • 支持?jǐn)U展圖片處理和圖片格式

先看一個Kingfisher的基本用法:從網(wǎng)絡(luò)上設(shè)置一張基本的圖片

let url = URL(string: "http://mvimg2.meitudata.com/55fe3d94efbc12843.jpg")
imageView.kf.setImage(with: url)

美女躍然屏上(模擬器截圖)

Kingfisher從url下載圖片,將圖片存儲在內(nèi)存緩存和磁盤緩存岩馍,然后將它展示在imageView上碉咆。當(dāng)使用同樣的代碼后(url不變),就會直接從內(nèi)存中獲取之前緩存的圖片并立即顯示出來蛀恩。

要求

  • iOS 8.0+ / macOS 10.10+
  • Swift 3(Kingfisher 3.x), Swift 2.3(Kingfisher 2.x)

Kingfisher 3.0遷移指導(dǎo) : 從早期版本升級到Kingfisher 3.0以上

集成

注:這里只介紹CocoaPods的集成方式

source 'https://gitgub.com/CocoaPods/Specs.git'
platform :ios, '8.0'

target '你的工程名' do
use_frameworks!
    pod 'Kingfisher', '~> 3.0'
end

then

pod install

基本使用

直接設(shè)置一張url圖片

if let url = URL(string: "http://mvimg2.meitudata.com/55fe3d94efbc12843.jpg") {
    imgView.kf.setImage(with: url)
}

詮釋:使用直接設(shè)置的方法疫铜,Kingfisher首先會嘗試從緩存中去取,如果沒有双谆,則直接下載圖片并且緩存下來以備后用壳咕。此外,Kingfisher默認(rèn)使用absoluteString of url(即絕對url)作為cacheKey以方便再次加載該圖片的時候去緩存中根據(jù)cacheKey(也就是圖片url)查找顽馋,通俗來說就是把圖片的整個鏈接作為cacheKey來緩存在本地谓厘。

指定一個cacheKey緩存圖片

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

設(shè)置占位符圖片

Kingfisher中,為了防止加載網(wǎng)絡(luò)圖片失敗寸谜,提供了一個設(shè)置占位符圖片功能竟稳,也就是說,當(dāng)網(wǎng)絡(luò)加載過程中或者圖片加載失敗時熊痴,就使用自定義的默認(rèn)圖片來代替顯示他爸。

if let url = URL(string: "http://mvimg2.meitudata.com/55fe3d94efbc12843.jpg") {
    imageView.kf.setImage(with: url, placeholder: placeholder_image, options: nil, progressBlock: nil, completionHandler: nil)
}

下載完成回調(diào)

if let url = URL(string: "http://mvimg2.meitudata.com/55fe3d94efbc12843.jpg") {
    imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: nil, completionHandler: { (image, error, cacheType, imageUrl) in
        
        image       // 為 nil 時,表示下載失敗
        
        error       // 為 nil 時愁拭,表示下載成功讲逛, 非 nil 時,就是下載失敗的錯誤信息
        
        cacheType   // 緩存類型岭埠,是個枚舉盏混,分以下三種:
                    // .none    圖片還沒緩存(也就是第一次加載圖片的時候)
                    // .memory  從內(nèi)存中獲取到的緩存圖片(第二次及以上加載)
                    // .disk    從磁盤中獲取到的緩存圖片(第二次及以上加載)
        
        imageUrl    // 所要下載的圖片的url
        
    })
}

加載菊花

Kingfisher提供了一個在下載圖片過程中顯示加載菊花的功能,圖片加載成功后菊花自動消失惜论,可以通過設(shè)置indicatorType來顯示菊花

IndicatorType是一個枚舉

public enum IndicatorType {
    /// 默認(rèn)沒有菊花
    case none
    /// 使用系統(tǒng)菊花
    case activity
    /// 使用一張圖片作為菊花许赃,支持gif圖
    case image(imageData: Data)
    /// 使用自定義菊花,要遵循Indicator協(xié)議
    case custom(indicator: Indicator)
}

設(shè)置方式 1 : 使用系統(tǒng)菊花

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

演示效果(加載的是我微博上的一張圖片)

設(shè)置方式 2 :使用gif圖作為加載菊花

let path = Bundle.main.path(forResource: "myImage", ofType: "gif")!
let data = try! Data(contentsOf: URL(fileURLWithPath: path))
imageView.kf.indicatorType = .image(imageData: data)
imageView.kf.setImage(with: url)

演示效果

設(shè)置方式 3 :自定義菊花馆类,遵循 Indicator協(xié)議


let myIndicator = CustomIndicator()
imageView.kf.indicatorType = .custom(indicator: myIndicator)
imageView.kf.setImage(with: url)

struct CustomIndicator: Indicator {
    
    var view: IndicatorView = UIView()
    
    func startAnimatingView() {
        view.isHidden = false
    }
    
    func stopAnimatingView() {
        view.isHidden = true
    }
    
    init() {
        view.backgroundColor = UIColor.magenta
    }
}

詮釋:Indicator是一個協(xié)議混聊,如果我們要實現(xiàn)自定義菊花加載,只需要遵循這個協(xié)議即可乾巧,另外必須得說的是句喜,Indicator協(xié)議中有一個屬性viewCenter我們不需要在遵循協(xié)議的時候去實現(xiàn),因為喵神已經(jīng)為我們提供了默認(rèn)實現(xiàn)(我還因為這個問題在github上問過他沟于,突然覺得好蠢...)

設(shè)置方式 4 : 根據(jù)實時下載圖片的數(shù)據(jù)做進(jìn)度條加載或者菊花加載(靈活咳胃,比例為:圖片已下載數(shù)據(jù) / 圖片總數(shù)據(jù))

imageView.kf.setImage(with: url, placeholder: nil, options: nil, progressBlock: { (receivedData, totolData) in

    let percentage = (Float(receivedData) / Float(totolData)) * 100.0
    
    print("downloading progress is: \(percentage)%")
    
    // 這里用進(jìn)度條或者繪制view都可以,然后根據(jù) percentage% 表示進(jìn)度就行了
    
}, completionHandler: nil)

設(shè)置過渡動畫旷太,漸變效果(圖片下載結(jié)束后)

imageView.kf.setImage(with: url, placeholder: nil, options: [.transition(.fade(0.4))], progressBlock: nil, completionHandler: nil)

詮釋: 在Kingfisher中展懈,有一個options, 我們可以做一些選擇销睁,Kingfisher里面目前包含了18種選擇,在圖片下載結(jié)束后存崖,為了實現(xiàn)一些效果冻记,我們可以實現(xiàn)上面的漸變效果,或者還有更多的翻滾效果来惧! 但是Kingfisher冗栗,上面的這個過渡動畫值只是針對圖片是從web下載時調(diào)用,如果是從內(nèi)存或磁盤中取時是不會有這個效果的违寞,雖然里面也有一個枚舉值強(qiáng)制動畫forceTransition,但是似乎暫時作者還沒有實現(xiàn)這個功能贞瞒。

設(shè)置圖片模糊效果

let processor = BlurImageProcessor(blurRadius: 25)
imageView.kf.setImage(with: url, placeholder: nil, options: [.processor(processor)], progressBlock: nil, completionHandler: nil)

詮釋:還有很多其他選擇,可自行根據(jù)需要設(shè)置趁曼。

強(qiáng)制下載(跳過緩存军浆,直接從web下載圖片)

imageView.kf.setImage(with: url, placeholder: nil, options: [.forceRefresh], progressBlock: nil, completionHandler: nil)

強(qiáng)制從緩存中獲取圖片(緩存中沒有也不會從網(wǎng)絡(luò)下載)

imageView.kf.setImage(with: url, placeholder: nil, options: [.onlyFromCache], progressBlock: nil, completionHandler: nil)

給按鈕(UIButton)設(shè)置圖片或背景圖片

同設(shè)置UIImageView一樣, 我們也可以使用Kingfisher來給UIButton設(shè)置圖片, 用法相同:

button.kf.setImage(with: url, for: .normal, placeholder: nil, options: nil, progressBlock: nil, completionHandler: nil)
button.kf.setBackgroundImage(with: url, for: .normal, placeholder: nil, options: nil, progressBlock: nil, completionHandler: nil)

緩存 和 下載器

Kingfisher 由兩個主要組件組成:下載圖片的圖片下載器ImageDownloader挡闰、操作緩存的圖片緩存ImageCache乒融。我們也可以單獨使用其中任意一個。

  • 使用 ImageDownloader 下載圖片(不可以緩存圖片)
ImageDownloader.default.downloadImage(with: url, retrieveImageTask: nil, options: nil, progressBlock: { (receivedData, totalData) in
    receivedData     // 已接收圖片數(shù)據(jù)
    totalData           // 圖片總大小
}, completionHandler: { (image, error, url, data) in
    image       // 圖片
    error       // 下載失敗時的錯誤信息
    url         // 所要下載的圖片的url
    data        // 下載完成后的總數(shù)據(jù)
})
  • 使用 ImageCache存儲獲取圖片

存儲圖片:

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

獲取圖片:


// 獲取緩存檢查結(jié)果
let cacheCheckResult = ImageCache.default.isImageCached(forKey: "Specified_Keys")
print("cacheCheckResult is \(cacheCheckResult)")

// 從磁盤獲取圖片
let img1 = ImageCache.default.retrieveImageInDiskCache(forKey: "Specified_Keys")
if let image = img1 {
   imageView.image = image
}
print("Image1 in disk cache is \(String(describing: img1))")

// 從磁盤獲取圖片
let img2 = ImageCache.default.retrieveImageInDiskCache(forKey: "Specified_Keys", options: [.transition(.fade(0.5))])
print("Image2 in disk cache is \(String(describing: img2))")

// 從內(nèi)存獲取圖片
let image1 = ImageCache.default.retrieveImageInMemoryCache(forKey: "Specified_Keys")
print("image1 in memory cache is \(String(describing: image1))")

// 從內(nèi)存獲取圖片
let image2 = ImageCache.default.retrieveImageInMemoryCache(forKey: "Specified_Keys", options: [.transition(.fade(0.5))])
print("image2 in memory cache is \(String(describing: image2))")

// 直接獲取圖片(獲取后才知道是 memory 還是 disk)
ImageCache.default.retrieveImage(forKey: "Specified_Keys", options: nil) { (image, cacheType) in
   print("image is \(String(describing: image))")
   print("cacheType is \(cacheType)")
   self.imageView.image = image
}

演示效果:

Markdown

打印結(jié)果:

test
cacheCheckResult is CacheCheckResult(cached: true, cacheType: Optional(Kingfisher.CacheType.memory))
Image1 in disk cache is Optional(<UIImage: 0x600000281b80>, {2448, 3264})
Image2 in disk cache is Optional(<UIImage: 0x600000281cc0>, {2448, 3264})
image1 in memory cache is Optional(<UIImage: 0x600000280910>, {2448, 3264})
image2 in memory cache is Optional(<UIImage: 0x600000280910>, {2448, 3264})
image is Optional(<UIImage: 0x600000280910>, {2448, 3264})
cacheType is memory

分析: 從結(jié)果分析來看摄悯,但你使用Kingfisher來存儲圖片時赞季,默認(rèn)是存儲在memorydisk; 第一次run奢驯, 先是從內(nèi)存中獲取圖片(此時內(nèi)存中和磁盤中都有緩存)申钩;若我們不卸載模擬器上的app, 然后再次運行模擬器,也即是殺死進(jìn)程瘪阁,那么我們看到的將是從disk中獲取圖片撒遣,因為在殺死進(jìn)程后,內(nèi)存中的緩存被清空(回收內(nèi)存)管跺,只有磁盤中有緩存; 若接著再次獲取緩存圖片(不殺死進(jìn)程)义黎,那么我們又看到是從memory中獲取到的圖片,因為第一次從disk中獲取圖片后豁跑,就會將disk中的緩存圖片放在內(nèi)存中進(jìn)行緩存廉涕,在不殺死進(jìn)程的情況下,會直接從內(nèi)存中獲韧摹:伞!卸夕!看一下下面的再次演示:

Markdown

當(dāng)然层释,我們也可以直接指定是需要緩存到磁盤還是內(nèi)存

ImageCache.default.store(image,                      // 圖片
                         original: data,             // 原圖片的data數(shù)據(jù)(Kingfisher推薦有,原因我后續(xù)有空會說)
                         forKey: "Specified_Keys",   // 指定key
                         processorIdentifier: "",    // 處理器標(biāo)識符(使用處理器處理圖片時娇哆,把這個標(biāo)識傳給它),標(biāo)識會用來給 key 和 processor 的組合產(chǎn)生一個對應(yīng)的key)
                         cacheSerializer: DefaultCacheSerializer.default,   // 緩存序列化,這里默認(rèn)
                         toDisk: false,              // 是否緩存到disk(磁盤)
                         completionHandler: nil)     // 完成回調(diào)

移除緩存圖片

// 移除 key 為 Specified_Keys 的緩存圖片,從內(nèi)存和磁盤中都移除
ImageCache.default.removeImage(forKey: "Specified_Keys")

// 只清理內(nèi)存中的緩存
ImageCache.default.removeImage(forKey: "Specified_Keys", processorIdentifier: "", fromDisk: false, completionHandler: nil)

限制(設(shè)置)磁盤的最大緩存(單位:字節(jié))

// 設(shè)置磁盤的最大緩存容量為 10 M, 默認(rèn)是0碍讨,表示無限制
ImageCache.default.maxDiskCacheSize = 10 * 1024 * 1024

獲戎瘟Α(計算)當(dāng)前磁盤緩存大小

ImageCache.default.calculateDiskCacheSize { (usedDiskCacheSize) in
    print("usedDiskCacheSize is \(usedDiskCacheSize)")
}

手動清理緩存

  • 立即清除內(nèi)存緩存
ImageCache.default.clearMemoryCache()
  • 清除磁盤緩存(異步操作)
ImageCache.default.clearDiskCache()
  • 清除過期或超過磁盤緩存大小的緩存(異步操作)
ImageCache.default.cleanExpiredDiskCache()

注意:當(dāng)你的app接收到內(nèi)存警告(memory warning)的時候,Kingfisher會凈化內(nèi)存緩存勃黍,也就是說宵统,在需要的時候,Kingfisher會主動清理一些已過期或者超過緩存尺寸大小的緩存覆获,因此一般而言马澈,沒有必要自己手動去清理緩存,而這些清理緩存方法的存在主要在于以防你想要用戶有更多對緩存進(jìn)行操作的情況弄息。比如有時候痊班,有部分app習(xí)慣在設(shè)置里面加一個清理緩存的交互,為了方便摹量,你可以根據(jù)需要調(diào)用這些手動清理緩存的方法涤伐。

設(shè)置存儲在磁盤中的最長的緩存持續(xù)時間

// 5天后磁盤緩存將過期
ImageCache.default.maxCachePeriodInSecond = 5 * 24 * 60 * 60

注意:默認(rèn)是一個周(即7天),單位是 秒缨称。必須注意的是凝果,如果設(shè)置成一個負(fù)值(比如 -1 )那么磁盤緩存決不會過期!

將一個默認(rèn)路徑擴(kuò)展添加到每個緩存文件

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

注意:如果你是在macOS上使用Kingfisher并且想要添加拖放的操作的時候特別有用睦尽,大多數(shù)web輸入字段不接受沒有路徑擴(kuò)展的文件器净。什么意思呢?比如当凡,你想在一個可拖進(jìn)圖片進(jìn)行識別的表單中拖拽一張沒有后綴.jpgpng的格式圖片進(jìn)去山害,實際上你操作的時候表單框是拒絕你的,你無法拖進(jìn)去宁玫,如果你加了圖片后綴識別名jpg等后粗恢,就可以拖進(jìn)去了,這就是這個方法的莫大好處欧瘪,當(dāng)然眷射,如果你是iOS客戶端開發(fā),就忽略這個功能佛掖,因為作者說了妖碉,這個實在macOS桌面應(yīng)用上特別有用。

為默認(rèn)圖片下載器設(shè)置超時持續(xù)時間

// 設(shè)置成30秒芥被,默認(rèn)是15秒
ImageDownloader.default.downloadTimeout = 30

好了欧宜,到此為止,對于Kingfisher的基本使用介紹差不多了拴魄,后面還有很多方法冗茸,包括自定義下載器和緩存席镀、取消下載任務(wù)或獲取任務(wù)、在發(fā)送前修改請求等等 我們將在后面陸續(xù)介紹夏漱,對于喜歡Kingfisher的小伙伴們也可以自己深入研究豪诲,基本的使用設(shè)置事實上很簡單,但盡管如此挂绰,Kingfisher中的很多地方還是很值得一探究竟的屎篱。

歡迎加入 iOS(swift)開發(fā)互助群:QQ群號:558179558, 相互討論和學(xué)習(xí)葵蒂!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末交播,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子践付,更是在濱河造成了極大的恐慌秦士,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荔仁,死亡現(xiàn)場離奇詭異伍宦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)乏梁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門次洼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人遇骑,你說我怎么就攤上這事卖毁。” “怎么了落萎?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵亥啦,是天一觀的道長。 經(jīng)常有香客問我练链,道長翔脱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任媒鼓,我火速辦了婚禮届吁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绿鸣。我一直安慰自己疚沐,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布潮模。 她就那樣靜靜地躺著亮蛔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪擎厢。 梳的紋絲不亂的頭發(fā)上究流,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天辣吃,我揣著相機(jī)與錄音,去河邊找鬼芬探。 笑死齿尽,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的灯节。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼绵估,長吁一口氣:“原來是場噩夢啊……” “哼炎疆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起国裳,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤形入,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后缝左,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亿遂,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年渺杉,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛇数。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡是越,死狀恐怖耳舅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情倚评,我是刑警寧澤浦徊,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站天梧,受9級特大地震影響盔性,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜呢岗,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一冕香、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧敷燎,春花似錦暂筝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至饭豹,卻和暖如春鸵赖,著一層夾襖步出監(jiān)牢的瞬間务漩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工它褪, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留饵骨,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓茫打,卻偏偏與公主長得像居触,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子老赤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容