内容简介:野指针指向一个已删除的对象或未申请访问受限内存区域的指针。特别要指出的是野指针不是空指针。一提到上面的这段代码就会造成循环引用。那我们怎么破除呢?通常的做法都是使用
野指针指向一个已删除的对象或未申请访问受限内存区域的指针。特别要指出的是野指针不是空指针。
Block
一提到 Block
大家肯定都知道要说的是循环引用。在 ARC
中,如果两个对象相互持有对方,就会造成循环引用,导致内存无法释放。在 Block
中,最常用的场景则是, self
持有 block
, block
中又持有了 self
。例如下方一段代码:
@property (nonatmaic, copy) Block dataChanged; - (void)setUpModel{ XYModel *model = [XYModel new]; model.dataChanged = ^(NSString *title) { self.titleLabel.text = title; }; self.model = model; } 复制代码
上面的这段代码就会造成循环引用。那我们怎么破除呢?通常的做法都是使用 weakSelf
来处理,即:
- (void)setUpModel { XYModel *model = [XYModel new]; __weak typeof(self) weakSelf = self; model.dataChanged = ^(NSString *title) { weakSelf.titleLabel.text = title; }; self.model = model; } 复制代码
或许你还看到另外一种不是很一样的版本:
- (void)setUpModel { XYModel *model = [XYModel new]; __weak typeof(self) weakSelf = self; model.dataChanged = ^(NSString *title) { __strong typeof(self) strongSelf = weakSelf; strongSelf.titleLabel.text = title; }; self.model = model; } 复制代码
对比一下,多了一个 strongSelf
。那为什么又要多加一个 strongSelf
呢?
考虑一下下面的代码,
__weak __typeof__(self) weakSelf = self; dispatch_group_async(_operationsGroup, _operationsQueue, ^{ [weakSelf doSomething]; [weakSelf doSomethingElse]; }); 复制代码
在 doSomething
时, weakSelf
不会被释放,但是在 doSomethingElse
时, weakSelf
有可能被释放。
这个时候就遇到了野指针问题,回答了一开始的题目。
在这里就需要用到 strongSelf
,使用 __strong
确保在 Block
内, strongSelf
不会被释放。
小结
-
在使用
Block
时,如遇到循环引用问题,可以使用__weak
来破除循环引用。 -
如果在
Block
内需要多次访问__weak
变量,则需要使用__strong
来保持变量不会被释放。
SDWebImage
中为什么要解码图片
要说明这么问题我们需要先了解一下在 iOS
中,图片显示的流程。
概括来说,从磁盘中加载一张图片,并将它显示到屏幕上,中间的主要工作流如下:
假设我们使用 imageWithContentsOfFile:
方法从磁盘中加载一张图片,这个时候的图片并没有解压缩;
然后将生成的 UIImage
赋值给 UIImageView
;
接着一个隐式的 CATransaction
捕获到了 UIImageView
图层树的变化;
在主线程的下一个 run loop
到来时, Core Animation
提交了这个隐式的 transaction
,这个过程可能会对图片进行 copy
操作,而受图片是否字节对齐等因素的影响,这个 copy
操作可能会涉及以下部分或全部步骤:
-
分配内存缓冲区用于管理文件
IO
和解压缩操作; - 将文件数据从磁盘读到内存中;
-
将压缩的图片数据解码成未压缩的位图形式,这是一个非常耗时的
CPU
操作; -
最后
Core Animation
使用未压缩的位图数据渲染UIImageView
的图层。
在上面的步骤中,我们提到了图片的解压缩是一个非常耗时的 CPU
操作,并且它默认是在主线程中执行的。那么当需要加载的图片比较多时,就会对我们应用的响应性造成严重的影响,尤其是在快速滑动的列表上,这个问题会表现得更加突出。
这里顺便提一下 imageNamed:
和 imageWithContentsOfFile:
的区别,这两个 API
都需要解码,并且工作流程都是一致的。不过 imageNamed:
会做缓存处理,在下一次用到相同的资源时,就会从缓存里面读取。而 imageWithContentsOfFile:
则不会。所以网上大多文章都会告诉你,多次使用的小图片使用 imageNamed:
加载,一次性使用的大图片使用 imageWithContentsOfFile:
加载。
对于上面引用的流程中最后提到,当有大量图片滑动时就会造成主线程的卡顿,原因就是解码图片在主线程中操作的。那有什么办法避免呢? 我在查询关于这个问题的相关资料时,发现有些博客给出了2种方案:
-
我们不使用
imageNamed:
加载图片,使用其他的方法,比如imageWithContentsOfFile:
-
我们自己解码图片,可以把这个解码过程放到子线程
其实第一种方式没法避免卡顿。这就引出了为什么 SDWebImage
中需要自己解码图片。
在我们使用 UIImage
的时候,创建的图片通常不会直接加载到内存,而是在渲染的时候再进行解压并加载到内存。这就会导致 UIImage
在渲染的时候效率上不是那么高效。为了提高效率通过 decodedImageWithImage
方法把图片提前解压加载到内存,这样这张新图片就不再需要重复解压了,提高了渲染效率。这是一种空间换时间的做法。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 从一道面试题说起—js隐式转换踩坑合集
- HashMap源码全解析从一道面试题说起:请一行一行代码描述下hashmap put方法
- 从一次分享说起
- 从安卓 WebView 更新说起
- 从排序这个小问题说起
- 从 CNN 性能优化说起(一)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript & jQuery交互式Web前端开发
[美]达克特(Duckett,J.) / 杜伟、柴晓伟、涂曙光 / 清华大学出版社 / 2015-6-9 / 79.80元
欢迎选择一种更高效的学习JavaScript和jQuery的方式。 你是一名JavaScript新手?或是您曾经向自己的Web页面上添加过一些脚本,但想以一种更好的方式来实现它们?本书非常适合您。本书不仅向您展示如何阅读和编写JavaScript代码,同时还会以一种简单且视觉化的方式,教您有关计算机编程的基础知识。阅读本书之前,您只需要对HTML和CSS有一些了解即可。 通过将编程理论......一起来看看 《JavaScript & jQuery交互式Web前端开发》 这本书的介绍吧!