从两道面试题说起

栏目: IOS · 发布时间: 7年前

内容简介:野指针指向一个已删除的对象或未申请访问受限内存区域的指针。特别要指出的是野指针不是空指针。一提到上面的这段代码就会造成循环引用。那我们怎么破除呢?通常的做法都是使用

野指针指向一个已删除的对象或未申请访问受限内存区域的指针。特别要指出的是野指针不是空指针。

Block

一提到 Block 大家肯定都知道要说的是循环引用。在 ARC 中,如果两个对象相互持有对方,就会造成循环引用,导致内存无法释放。在 Block 中,最常用的场景则是, self 持有 blockblock 中又持有了 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种方案:

  1. 我们不使用 imageNamed: 加载图片,使用其他的方法,比如 imageWithContentsOfFile:

  2. 我们自己解码图片,可以把这个解码过程放到子线程

其实第一种方式没法避免卡顿。这就引出了为什么 SDWebImage 中需要自己解码图片。

在我们使用 UIImage 的时候,创建的图片通常不会直接加载到内存,而是在渲染的时候再进行解压并加载到内存。这就会导致 UIImage 在渲染的时候效率上不是那么高效。为了提高效率通过 decodedImageWithImage 方法把图片提前解压加载到内存,这样这张新图片就不再需要重复解压了,提高了渲染效率。这是一种空间换时间的做法。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Pro CSS and HTML Design Patterns

Pro CSS and HTML Design Patterns

Michael Bowers / Apress / April 23, 2007 / $44.99

Design patterns have been used with great success in software programming. They improve productivity, creativity, and efficiency in web design and development, and they reduce code bloat and complexit......一起来看看 《Pro CSS and HTML Design Patterns》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

SHA 加密
SHA 加密

SHA 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具