GCD和NSOperation多线程技术
第一讲 GCD
GCD会管理多线程的生命周期
GCD底层线程池,队列跟底层线程池之间的交互,底层线程池对线程进行了复用,使用效率要高
GCD跟NSThread对比
- 开不开线程,和执行任务的函数有关
- 同步不开
- 异步开
- (异步)开几条线程,和队列有关
- 串行队列最多开一条
- 并发队列开N条,具体条数由GCD决定!
主队列:
主队列同步会死锁:
注意主队列同步也可以不死锁,具体情况具体对待
主队列异步: 不会开启线程,在主线程中执行,但是主队列中的任务需要等待主线程中任务执行完毕之后才能执行
barrier阻塞:
会先循环执行完下载完成(所有异步执行完之后再执行barrier的block中代码),同一线程中顺序执行
注意:
dispatch_barrier_async
必须使用自定义队列,否则执行效果和全局队列一致dispatch_once 只执行一次的代码,注意单例中的static能够保证在block中局部变量可以记录保存在静态区,不会被销毁
dispatch_once是同步的,是线程安全的, dispatch_once内部也有一把锁,这把锁的性能很高
dispatch_group 调度组 dispatch_group_notify 异步的
dispatch_after 延迟操作- 异步执行的 因此在dispatch_after的block中执行的任务是在子线程中执行
第二讲 NSOperation
iOS8之后,GCD底层的线程池特别慷慨,只要要就给,可以开很多条线程
NSOperation是iOS2.0推出的,GCD是iOS4.0推出的
ARC是Xcode4.2推出的
NSInvocationOperation和NSBlockOperation的使用(都是异步并发执行的)
线程间通讯:
NSOperation和GCD的对比:
NSOperation设置最大并发数 setMaxConcurrentOperationCount
暂停继续(队列的挂起状态),挂起的是队列,不会影响正在执行的操作
取消,暂停和继续
依赖关系
异步下载图片
在异步下载图片的时候的问题及解决:
当异步下载图片之后,由于blockOperation是异步下载的,当返回cell的时候image还未下载下来,所以由于cell的imageView懒加载,并未显示图片,当点击或者上下滚动才显示
解决办法:占位图片提前设置imageView,固定imageView的大小
但是此时又有问题,占位图片太大,下载图片小,所以一开始显示占位图片大点击cell之后显示小的下载图片
解决办法:自定义cell,设置好imageView的大小,可以完整显示占位图片和下载图片
然而还有问题,此时图片每次滚动都会下载,并且当网速不同会导致图片错位,原因:比如第一个cell的图片下载很快,第九个之后就很慢,当第一个cell进入缓存池之后,第十个cell会进行cell复用,此时cell的图片下载很慢,图片还未下载完,当在往上滚动的时候,第一个cell会复用第十个 cell,由于第一个cell图片下载快,所以显示之后过几秒会再下载显示第十个cell未下载完的图片,从而发生图片错位的现象。
解决办法:利用MVC模式,在模型中定义图片属性,将图像异步保存在模型中,并刷新当前行调用数据源方法,在cell中判断模型是否有图片,显示模型中存储的图像。这样同时解决了不断从网络下载的问题
操作缓冲池:
为什么需要操作缓冲池?因为在下载网络图片的时候,当网络很慢,而用户快速滑动,比如第一个cell的图片没有下载完,于是会在创建一个操作添加到队列中,这样会造成资源的浪费
下载结束,清除操作缓冲
图像缓冲池的引入
由于模型内保存图片跟模型绑定的很紧,当接收到内存警告的时候不好释放,所以需要引入图像缓冲池,类似于操作缓冲池,用url作为key用字典缓冲
layoutsubviews方法的调用
内存警告清理缓冲池
实现沙盒缓存见SDWebImage