swift_高阶函数(嵌套函数)的使用心得

源码地址
github
此例子是在写相册选择器时获取图片资源时所用,
主要解决了获取图片的缓存问题和尺寸问题,简化了逻辑和结构
使代码十分清晰明了且易于理解


此处只显示核心代码,详细见源码

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根据PHAsset对象获取实际图片,
那么问题来了:

  • 我是用collectionView展示的,那么数据源我保存什么,图片数组?PHAsset数组?
    答:图片资源较大,占用内存较多,且分为缩略图和高清图,直接保存会占用极多内存,尤其在图片资源较多的时候;那么就可以保存PHAsset,这个只是图片资源的描述,并不是图片本身,占用内存极小(相对图片来说),且可以根据该对象动态选择获取什么尺寸的图片

  • 如何缓存图片资源?
    答:翻找Photos的API,找到了PHCachingImageManager ,可以批量缓存,缓存后再获取速度极快,且占用内存小。PS:经测试:在手机大约1000张时,缓存原图 只占用20M,缩略图只有13M

  • 如何方便快捷的获取图片,因为在collectionView展示,我想只根据indexPath.row序号就能获取缓存的图片,而不是每次根据序号取出asset对象,再传入其余参数配置(要和缓存时参数配置一样)才能取出图片?
    答:想到了Swift文档中关于 ''嵌套函数''的介绍,在swift中函数作为一等公民,可以当做一般对象使用,可以在内部函数内部声明新的函数,并把此函数当做结果返回出去,同时,内部函数拥有访问外部函数变量的权限,且拥有类似懒加载的特性(内部函数并不是立马执行,而是每调用一次才执行一次)

详解getImageByConfig()函数

无论获取缩略图还是高清图,我最都是调用内部的这个方法,看看这个方法都做了什么。

  1. 根据参数配置,做了图片缓存
  2. 返回了一个图片生成器

这个图片生成器又做了什么?
由于getImage()是内部函数,所以它可以拿到外部函数的所有参数,包括asset集合和其余参数配置,然后该函数根据指定的索引序号获取图片。

使用

    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
    }

在进入控制器时获取了asset集合,并对图片进行了缓存,并将函数返回的图片生成器的函数保存当前类的全局变量中,self.getThumbnail,self.getHighImage(这两个变量都是函数类型的)
在需要使用的时候,给该变量传入所需的索引号,就能方便的获取事先缓存好的图片。是不是很简洁!

个人感觉:
内部函数类似于block,可以访问外部函数的变量
block是匿名函数(没有方法名),若存在于某个函数内也算是内部函数吧

自己都被swift这种简洁优雅的实现震撼了,将函数的依赖降到了最低。

看~灰机~灰机灰过来了~灰机又灰过去了~
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,448评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,019评论 4 62
  • 父类:NSObject 提供获取或生成预览缩略图和全尺寸图片,或者视频数据的方法。 一、概述 使用这些方法来获取全...
    Shmily落墨阅读 10,478评论 5 6
  • 很久没去过书店,前几天偶然去了一次,却发现书架上摆满了“一本书读懂XXX”“一分钟学会XXX”的书籍,居然还很受热...
    因果之间阅读 528评论 0 2
  • 我的这位朋友身材高大,肩膀宽阔,有点耸肩显得微微驼背,站在面前让人很有压迫感。 他的额头很宽,尽管留着的头发短到几...
    杨彤宇阅读 193评论 0 1