给AsyncDisplayKit(Texture)替换网络图片下载缓存框架

前言 为了方便管理图片缓存,统一缓存文件夹和缓存方法,将AsyncDisplayKit自带的PINRemoteImage插件, 替换为项目在用的Kingfisher、SDWebImage。 1import Kingfisher 2 3extension ASNetworkImageNode { 4 static func imageNode() -> ASNetworkImageNode { 5 return ASNetworkImageNode(cache: ASImageManager.shared, downloader: ASImageManager.shared) 6 } 7} 8 9class ASImageManager: NSObject, ASImageDownloaderProtocol, ASImageCacheProtocol { 10 11 static let shared = ASImageManager() 12 private override init() {} 13 14 func downloadImage(with url: URL, callbackQueue: DispatchQueue, downloadProgress: ASImageDownloaderProgress?, completion: @escaping ASImageDownloaderCompletion) -> Any? { 15 16 ImageDownloader.default.downloadTimeout = 30.0 17 var operation: DownloadTask? 18 operation = ImageDownloader.default.downloadImage(with: url, options: nil, progressBlock: { (received, expected) in 19 if downloadProgress != nil { 20 callbackQueue.async(execute: { 21 let progress = expected == 0 ? 0 : received / expected 22 downloadProgress?(CGFloat(progress)) 23 }) 24 } 25 }) { (result) in 26 switch result { 27 case .success(let value): 28 callbackQueue.async(execute: { completion(value.image, nil, nil, nil) }) 29 ImageCache.default.store(value.image, original: value.originalData, forKey: url.cacheKey, toDisk: true) 30 case .failure(let error): 31 callbackQueue.async(execute: { completion(nil, error, operation, nil) }) 32 dPrint("Job failed: \(error.localizedDescription)") 33 } 34 } 35 36 return operation 37 } 38 39 func cancelImageDownload(forIdentifier downloadIdentifier: Any) { 40 if let task = downloadIdentifier as? DownloadTask { 41 task.cancel() 42 } 43 } 44 45 func cachedImage(with url: URL, callbackQueue: DispatchQueue, completion: @escaping ASImageCacherCompletion) { 46 ImageCache.default.retrieveImage(forKey: url.cacheKey) { (result) in 47 switch result { 48 case .success(let value): 49 callbackQueue.async { completion(value.image) } 50 case .failure(let error): 51 dPrint("Job failed: \(error.localizedDescription)") 52 } 53 } 54 } 55} 1import SDWebImage 2 3extension ASNetworkImageNode { 4 static func imageNode() -> ASNetworkImageNode { 5 return ASNetworkImageNode(cache: ASNetImageManage.shared, downloader: ASNetImageManage.shared) 6 } 7} 8 9class ASNetImageManage: NSObject, ASImageDownloaderProtocol, ASImageCacheProtocol { 10 11 static let shared = ASNetImageManage() 12 13 func downloadImage(with URL: URL, callbackQueue: DispatchQueue, downloadProgress: ASImageDownloaderProgress?, completion: @escaping ASImageDownloaderCompletion) -> Any? { 14 15 weak var weakOperation: SDWebImageOperation? 16 let operation = SDWebImageManager.shared.loadImage(with: URL, options: .retryFailed, progress: { (received, expected, url) in 17 if downloadProgress != nil { 18 callbackQueue.async(execute: { 19 let progress = expected == 0 ? 0 : received / expected 20 downloadProgress?(CGFloat(progress)) 21 }) 22 } 23 }) { (cachedImage, data, error, type, unknow, url) in 24 if let image = cachedImage { 25 callbackQueue.async(execute: { completion(image, nil, nil, nil) }) 26 return 27 } 28 callbackQueue.async(execute: { completion(nil, error, nil, nil) }) 29 } 30 weakOperation = operation 31 return weakOperation 32 } 33 34 func cancelImageDownload(forIdentifier downloadIdentifier: Any) { 35 if let downloadIdentifier = downloadIdentifier as? SDWebImageOperation { 36 downloadIdentifier.cancel() 37 } 38 } 39 40 func cachedImage(with URL: URL, callbackQueue: DispatchQueue, completion: @escaping ASImageCacherCompletion) { 41 42 if let key = SDWebImageManager.shared.cacheKey(for: URL) { 43 SDWebImageManager.shared.imageCache.queryImage(forKey: key, options: .allowInvalidSSLCertificates, context: nil) { (cachedImage, data, type) in 44 if let image = cachedImage { 45 callbackQueue.async(execute: { completion(image) }) 46 return 47 } 48 callbackQueue.async(execute: { completion(nil) }) 49 } 50 }else { 51 callbackQueue.async { 52 completion(nil) 53 } 54 } 55 56 } 57}

2020-08-03 · 3 min · 474 words · CubeGao

容易被人忽略的 NSCache

第一次见到NSCache,是在SDWebImage中。SDWebImage的内存缓存机制就是通过NSCache完成的。所以可能你不太了解这个类,但是其实一直在使用它。 为什么要使用NSCache? 我们通常用缓存来临时存储短时间使用但创建昂贵的对象。重用这些对象可以优化性能,因为它们的值不需要重新计算。另外一方面,这些对象对于程序来说不是紧要的,在内存紧张时会被丢弃。如果对象被丢弃了,则下次使用时需要重新计算。 NSCache是一个可变的集合,主要用来存储key-value对。它有着和NSMutableDictionary类似的API。实际上,NSCache就像是一个会自动移除对象来释放内存的NSMutableDictionary。 ( i d o o o o ) i i i i o d d d d b ) ) ) ) j s s r r e e e e e c t t m m t O O o o F b b v v o j j e e r e e O A K c c b l e t t j l y : : e O : ( ( c b ( i i t j i d d F e d ) ) o c ) o o r t k b b K s e j j e y y f f : o o ( r r i K K d e e ) y y k : : e ( ( y i i d d ) ) k k e e y y c o s t : ( N S U I n t e g e r ) n u m NSCahce与可变集合不同之处: ...

2019-11-11 · 2 min · 231 words · CubeGao

HTTP 协议中 GET 和 POST 的区别

关于HTTP HTTP(超文本传输协议)是一种请求/响应型的协议。 HTTP的语法大致如下: 客户端给服务端发送的请求,由三部分组成:请求行,消息报头,消息正文。 请求行:Method Request-URI HTTP-Version CRLF 例如: GET /form.html HTTP/1.1 /r/n 服务端给客户端发送的响应,也是三部分组成:状态行,消息报头,响应正文。 状态行:HTTP-Version Status-Code Reason-Phrase 例如: HTTP/1.1 200 OK /r/n 正写到这里,小A走过来说:Request-URL,你打错了一个字母? 其实没错! 1.URI的全称是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。 2.URL的全称是uniform resource locator,统一资源定位符。用来标识一个资源,还指明了如何定位这个资源。如: h t t p s : / / w w w . q q . c o m / i n d e x . h t m l 3.URN的全称是Uniform Resource Name,统一资源名称。通过名称来标识资源。如 m a i l t o : x x x @ q q . c o m 其中,URL,URN是URI的子集。 ...

2019-02-02 · 1 min · 101 words · CubeGao

聊聊 iOS 中的内存管理

对于开发者来说,内存管理几乎是一个永恒的话题。 内存管理对于编写出高效率的iOS APP是非常重要的,这是因为iOS是多任务系统,在同一时刻可能有多个应用程序共享内存,有时为了使某个任务更好地执行,iOS系统可能会对其它任务分配的内存进行移动,甚至删除。 现在被广泛使用的内存管理机制主要有GC和RC两种。 GC:垃圾回收机制,定期查找不再使用的对象,释放对象占用的内存。 RC:引用计数机制,采用引用计数来管理对象的内存,当需要持有一个对象时,使它的引用计数+1,当不需要再持有一个对象的时候,使它的引用计数-1;当一个对象的引用计数为0时,该对象就会被销毁。 Objective-c支持三种内存管理机制:GC,MRC,ARC。以前MacOS开发中是支持GC的,后面引入ARC后就弃用了GC机制。iOS开发中使用的是RC机制,从MRC到现在的ARC。 ###引用计数 可以看我之前的一篇关于引用计数。 ###MRC时代 基本内存管理规则:MRC下是要严格遵守引用计数内存管理规则。 内存管理模型是基于对象的所有权。任何对象都可以拥有一个或者多个所有者,但是一个对象最少要拥有一个所有者,它才会继续存在。如果对象没有所有者的,它将会被销毁。 ####四条内存管理策略: 1.自己生成的对象,自己持有 alloc/new/copy/mutableCopy等方法创建的对象,我们自己直接持有,它的RC初始值为1,我们可以直接使用,不需要使用的时候调用release释放。 2.非自己生成的对象,自己也能持有。 不通过上面方法创建的对象,它的RC初始值也为1,但是我们不能直接使用,要先调用retain,否则可能会crash。原因是因为这些方法内部是给对象调用了autorelease方法,所以这些对象是被添加到了自动释放池中了。 两种情况,程序没有手动指定@autoreleasepool,当runloop迭代结束时,会自动给释放池中的对象调用release方法。如果我们使用前不进行retain,刚好runloop迭代结束,对象的RC从1变成0,然后就被销毁了.我们去访问一个已经被销毁的对象,程序就会crash。 程序手动指定了@autoreleasepool,当时出了其作用域,对象会调用release方法,然后销毁,这个时候使用对象也会crash。 3.不再需要自己持有的对象时,释放。 不再需要持有或者使用对象的时候,就调用release或者autorelease方法进行释放。rc变成0时,就会调用dealloc方法销毁。 release立马rc-1,autorelease加入自动释放池,在合适的时候rc-1,实际上就是延迟释放。 4.非自己持有的对象,无需释放。 自己不是持有者,调用release的话,会crash。 ####实用的内存管理原则 使用访问器方法可以省略大量的retain和release 推荐使用访问器方法设置属性,一个是可以避免忘记写retain和release,第二个是触发kvo 不要在初始化和dealloc中使用访问器方法,原因是在初始化中使用访问器方法,self=[super init],首先会调用父类的访问器方法,然后如果子类重写了访问器方法,会去调用子类的访问器方法,而这个时候,子类实际上是没有初始化的,所以会出错。dealloc实际上是个反向的。就是子类先释放,再去调用父类。就是调用父类的dealloc时,会调用父类的访问器方法,如果子类重写了该访问器方法,就会去调用子类的访问器方法,但是子类已经释放掉了,也会出错。还有一个原因就是会触发KVO,在准备释放前,触发了kvo,即将释放的对象被持有了。就是出现莫名其妙的错误。 推荐使用@autoreleasepool,虽然mrc下,可以使用NSautoreleasepool,但是速度慢很多。 1.写的程序是非UI框架,比如命令行工具 2.循环创建大量的临时变量。 3.多线程中。比如创建辅助线程。 ###ARC时代 ARC时代,内存管理基本都交给编译器来处理了,对于开发者来说是十分友好了。 ARC的编译器有两部分,前端编译器和优化器。前端编译器会对每一个对象插入相应的release语句。类拥有的对象会在dealloc中释放。方法内创建的对象,前端编译器会在方法末尾自动插入release语句销毁它。优化器负责移除多余的retain和release操作语句。 但是还是有些地方需要注意的。 新增的几个关键字: __strong 强引用,用来保证对象不会被释放。 __weak 弱引用 释放时会置为nil __unsafe_unretained 弱引用 可能不安全,因为释放时不置为nil。悬垂对象。 __autoreleasing 对象被注册到autorelease pool中方法在返回时自动释放。 ####block使用中出现循环引用 _ _ _ _ } p p p _ p ; e e e w e r r r e r s s s a s d } o o o k o _ i ) n n n n t s ; 1 2 2 1 y p . _ . p a N = = n t b e t S a y l o c L [ [ m p o f h o [ [ e e c ( _ g P P o k & a ( e e = f * f @ r r ( = w t " s s @ s e e % o o " e ^ a r @ n n 张 l { k ( " 三 f S d , a a " ) e i s l l ; l s t l l w f p r o o e ) a o c c a t n ] ] k s c g S t h S i i e r _ e n n l o t l i i f n i f t t g m . ] ] = S e p ; ; e ( e s l D r e f I s l S o f = P n ; A 2 w T . e C n a H a k _ m S T e e I ) l M ; f E ; _ N O W , ( i n t 6 4 _ t ) ( 5 N S E C _ P E R _ S E C ) ) , d i s p a t c h _ g e t _ m a i n _ q u e u e ( ) , ^ { 使用weakSelf结合strongSelf的情况下,能够避免循环引用,也不会造成提前释放导致block内部代码无效。 在MRC下,应该使用__block。 ...

2018-08-23 · 11 min · 2273 words · CubeGao

聊聊 isa 和引用计数

大家都知道内存管理是通过引用计数管理对象的生命周期。 那isa和引用计数又有什么关系呢?先留着疑问。 ###isa指针 t s } t y t ; y p r p e u e A d R c C A d n e e t l e f p a p f o r o s o p s e b s i s a t s j n t q r e c i t r u u n _ s e u e c t o a r c t s b t t j t y o a e O o o p b n c B b e j t J a j c i C n c t _ n { _ _ h c s I i o a l t S n b t a a A s j s n _ t e r s c A a c e e V n t p * A c r C o I e * e l f L i s a A o d e s a B f ; n s I t ; c L a s l I a T c a s Y l n s ; a . s O s b . j e c t i v e - C c l a s s . 通过注释和代码不难发现,我们创建的一个对象或实例其实就是一个struct objc_object结构体。 ...

2018-05-03 · 9 min · 1732 words · CubeGao

在 Centos7.2 上安装编译 Swift

由于想用Swift写服务玩玩,准备在Centos7.2上部署一个Swift环境,能跑一下Perfect。 由于Docker的种种好处,当然是选择它来部署Swift环境。 安装Docker 更新yum包到最新。如果是生产机器务必慎重更新内核,避免出现不必要的问题。 1[root@fadaixiaohai ~]# yum update 执行 Docker 安装脚本。 1[root@fadaixiaohai ~]# curl -fsSL https://get.docker.com/ | sh 启动 Docker 进程。 1[root@fadaixiaohai ~]# service docker start 验证 docker 是否安装成功并在容器中执行一个测试的镜像。 1[root@fadaixiaohai ~]# docker run hello-world 2Hello from Docker! 大概两三分钟就安装好了,国内的服务器可能要用镜像加速会好点。 安装Swift 拉取Swift的镜像到本地。 1[root@fadaixiaohai ~]# docker pull swift 镜像拉取成功后就可以使用docker images列出当前我们拉取到本地的所有镜像: 1[root@fadaixiaohai ~]# docker images 2REPOSITORY TAG IMAGE ID CREATED SIZE 3swift latest 934835f58041 3 weeks ago 1.3GB 4hello-world latest f2a91732366c 4 months ago 1.85kB 我们都知道,操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。 ...

2018-03-30 · 2 min · 265 words · CubeGao

利用 Travis CI 自动构建 Github Pages

###背景 每次写完blog,都要在本地hexo环境编译,等编译完成后,再push到github,重复的动作,浪费的时间。 懒惰是互联网进步的第一动力!我能不能每次写完md,直接push到github,然后它自动编译,编译完成后,自己push到仓库主分支呢?肯定是可以的,答案就是使用Travis CI自动构建工具。 ###关联Github和Travis CI Github 有提供一个 Personal access tokens,这个 Token 与 账号密码 以及 SSH Keys 同样具有 Github 写入能力。 前往 Github 帐号 Settings 页面,在左侧选择 Personal Access Token,然后在右侧面板点击 “Generate new token” 来新建一个 Token。需要注意的是,创建完的 Token 只有第一次可见,之后再访问就无法看见(只能看见他的名称),因此要保存好这个值。 ###登录Travis CI关联对应项目 首先打开官方网站 travis-ci.org,然后使用 Github 账号登入 Travis CI,然后 Travis 中会列出你 Github 上面所有的仓库,以及你所属于的组织。 然后,勾选你需要 Travis 帮你自动构建的仓库,打开仓库旁边的开关,打开以后,Travis 就会监听这个仓库的所有变化了。 ![E1BF98EB2CB8D8E4E6E1F6E8E3BDC5EA.jpg][2] ###travis.yml配置 原理就是监控对应的文件,有push就开始构建。 l n # c d - # b - - i - s - - a - - - - - - - - - - - # b o - a o a i e n c f r n n d T c r n S f e n s n r h h t g c g c m c g g g g g E a l h g e r h e o : o x p t p i e e e i d i d v d i i i i i : n y e u _ a e c d r p m a m p x x r t t t t t t t c : x a j v : t e B e o l t o o _ . . B h o g s i o _ u _ r i l i : s c d c d / c c a c p u e e : s r m i i t n : n c g c l e h e p o o d o u i s # : - i o l n s s l r o p e p u n n d m s l : s C e d d s T t t e i n l c l b f f m h d 只 n t I s u t Z a a a p e o k o l i i . i 对 o a : l L a = l l n t y o y i g g t L h d b C e i l ' l l : h _ u _ c - i e e l a s f l A t g t g u u - f f x _ e c e : s h # # t i i s s m o e o j h # c i e p t m t e e r C 分 s i y a x 下 推 s a / r r " c y 支 n 缓 c / o 载 送 : s . . . T e c 构 # g 存 l S - 依 到 / t g n e r l 建 n e h c 赖 g / e i a m a e 声 o a l i $ r t m a v - 明 d n i t { / e i i q 环 e g h G l s u 境 _ h - u H " i 为 m a g b _ / x " C e n o i 的 R p x x I t o d ' 部 E u x x d u 分 F b x x A " e l # } l x x u h e i x x t t s 更 . c x x o t 文 改 d / " x p 件 时 e x B s 夹 区 p @ u : l g i / o m l / y a d $ _ i e { g l r G i . H t c a _ o t T m O " ` K d E a N t } e @ $ + { " G % H Y _ - R % E m F - } % " d m % a H s : t % e M r " : ` m " a s t e r ###Build Config ...

2018-02-06 · 6 min · 1239 words · CubeGao

读源码之 SDWebImage

###背景 SDWebImage是iOS开发过程中最常使用的一个网络图片库,包括图片的下载和缓存。 主要提供的功能如下: 1.提供UIImageView, UIButton, MKAnnotationView 的分类,用来加载网络图片,并进行缓存管理; 2.异步方式来下载网络图片 3.异步方式: memory (内存)+ disk (磁盘) 来缓存网络图片,LRU自动管理缓存; 4.后台图片解码,转换及压缩; 5.同一个 URL 不会重复下载; 6.失效的 URL 不会被无限重试; 7.支持 GIF动画 及 WebP 格式; 8.使用 GCD 和 ARC; 9.开启子线程进行耗时操作,不阻塞主线程; ###入口部分 在使用SDWebImage的时候,入口如下: [ s e l f . i m a g e V i e w s p d l _ a s c e e t h I o m l a d g e e r W I i m t a h g U e R : L [ : U [ I N I S m U a R g L e U i R m L a W g i e t N h a S m t e r d i : n @ g " : p @ l " a u c r e l h " o ] l d e r . p n g " ] ] ; 点进去,可以看到下面这些方法: ...

2017-11-02 · 32 min · 6624 words · CubeGao