源碼地址
github
此例子是在寫相冊選擇器時獲取圖片資源時所用,
主要解決了獲取圖片的緩存問題和尺寸問題,簡化了邏輯和結(jié)構(gòu)
使代碼十分清晰明了且易于理解
此處只顯示核心代碼,詳細(xì)見源碼
show me code
public typealias ImageOfIndex = (Int)-> UIImage
private let imageManager = PHCachingImageManager()
/// get thumbnail creater
///
/// - Parameters:
/// - assets: PHAsset list
/// - size: target size
/// - Returns: thumbnail creater
public func getThumbnailImage(_ assets: [PHAsset], targetSize size: CGSize) -> ImageOfIndex {
let options = PHImageRequestOptions()
options.deliveryMode = .opportunistic
options.isSynchronous = false
return getImageByConfig(options, assets, size)
}
/// get highImage creater
///
/// - Parameters:
/// - assets: PHAsset list
/// - size: target size
/// - Returns: highImage creater
public func getHighImage(_ assets: [PHAsset], targetSize size: CGSize) -> ImageOfIndex {
let options = PHImageRequestOptions()
options.deliveryMode = .highQualityFormat
options.isSynchronous = false
return getImageByConfig(options, assets, size)
}
/// get image creater by config
///
/// - Parameters:
/// - option: PHImageRequestOptions
/// - assets: PHAsset list
/// - size: target size
/// - Returns: image creater
private func getImageByConfig(_ option: PHImageRequestOptions, _ assets: [PHAsset], _ size: CGSize) -> ImageOfIndex {
imageManager.startCachingImages(for: assets, targetSize: size, contentMode: .aspectFill, options: option)
//image creater
func getImage(_ index: Int) -> UIImage {
let option = PHImageRequestOptions()
option.isSynchronous = true
var image = UIImage()
imageManager.requestImage(for: assets[index], targetSize: size, contentMode: .aspectFill, options: option, resultHandler:{(result, info)->Void in
image = result!
})
return image
}
return getImage;
}
剖析
ios8.0可以使用PHAsset獲取相冊辣卒、圖片等資源,由PHImageManager根據(jù)PHAsset對象獲取實(shí)際圖片睛榄,
那么問題來了:
我是用collectionView展示的荣茫,那么數(shù)據(jù)源我保存什么,圖片數(shù)組场靴?PHAsset數(shù)組啡莉?
答:圖片資源較大,占用內(nèi)存較多旨剥,且分為縮略圖和高清圖咧欣,直接保存會占用極多內(nèi)存,尤其在圖片資源較多的時候轨帜;那么就可以保存PHAsset,這個只是圖片資源的描述魄咕,并不是圖片本身,占用內(nèi)存極邪龈浮(相對圖片來說)哮兰,且可以根據(jù)該對象動態(tài)選擇獲取什么尺寸的圖片
如何緩存圖片資源毛萌?
答:翻找Photos的API,找到了PHCachingImageManager ,可以批量緩存喝滞,緩存后再獲取速度極快阁将,且占用內(nèi)存小。PS:經(jīng)測試:在手機(jī)大約1000張時右遭,緩存原圖 只占用20M,縮略圖只有13M
如何方便快捷的獲取圖片做盅,因?yàn)樵赾ollectionView展示,我想只根據(jù)indexPath.row序號就能獲取緩存的圖片窘哈,而不是每次根據(jù)序號取出asset對象言蛇,再傳入其余參數(shù)配置(要和緩存時參數(shù)配置一樣)才能取出圖片?
答:想到了Swift文檔中關(guān)于 ''嵌套函數(shù)''的介紹宵距,在swift中函數(shù)作為一等公民,可以當(dāng)做一般對象使用吨拗,可以在內(nèi)部函數(shù)內(nèi)部聲明新的函數(shù)满哪,并把此函數(shù)當(dāng)做結(jié)果返回出去,同時劝篷,內(nèi)部函數(shù)擁有訪問外部函數(shù)變量的權(quán)限哨鸭,且擁有類似懶加載的特性(內(nèi)部函數(shù)并不是立馬執(zhí)行,而是每調(diào)用一次才執(zhí)行一次)
詳解getImageByConfig()函數(shù)
無論獲取縮略圖還是高清圖娇妓,我最都是調(diào)用內(nèi)部的這個方法像鸡,看看這個方法都做了什么。
- 根據(jù)參數(shù)配置哈恰,做了圖片緩存
- 返回了一個圖片生成器
這個圖片生成器又做了什么只估?
由于getImage()是內(nèi)部函數(shù),所以它可以拿到外部函數(shù)的所有參數(shù)着绷,包括asset集合和其余參數(shù)配置蛔钙,然后該函數(shù)根據(jù)指定的索引序號獲取圖片。
使用
internal var getThumbnail: ImageOfIndex?
internal var getHighImage: ImageOfIndex?
private func getAssetsImage() {
DispatchQueue.global().async {
self.getThumbnail = self.asset.getThumbnailImage(self.assetsList!, targetSize: self.flowLayout.itemSize)
self.getHighImage = self.asset.getHighImage(self.assetsList!, targetSize: UIScreen.main.bounds.size)
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell: YHPhotoThumbnailCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! YHPhotoThumbnailCell;
cell.setImage(getThumbnail!(indexPath.row))
return cell
}
在進(jìn)入控制器時獲取了asset集合荠医,并對圖片進(jìn)行了緩存吁脱,并將函數(shù)返回的圖片生成器的函數(shù)保存當(dāng)前類的全局變量中,self.getThumbnail彬向,self.getHighImage(這兩個變量都是函數(shù)類型的)
在需要使用的時候兼贡,給該變量傳入所需的索引號,就能方便的獲取事先緩存好的圖片娃胆。是不是很簡潔遍希!
個人感覺:
內(nèi)部函數(shù)類似于block,可以訪問外部函數(shù)的變量
block是匿名函數(shù)(沒有方法名),若存在于某個函數(shù)內(nèi)也算是內(nèi)部函數(shù)吧
自己都被swift這種簡潔優(yōu)雅的實(shí)現(xiàn)震撼了里烦,將函數(shù)的依賴降到了最低孵班。
看~灰機(jī)~灰機(jī)灰過來了~灰機(jī)又灰過去了~