内容简介:野指针指向一个已删除的对象或未申请访问受限内存区域的指针。特别要指出的是野指针不是空指针。一提到上面的这段代码就会造成循环引用。那我们怎么破除呢?通常的做法都是使用
野指针指向一个已删除的对象或未申请访问受限内存区域的指针。特别要指出的是野指针不是空指针。
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
方法把图片提前解压加载到内存,这样这张新图片就不再需要重复解压了,提高了渲染效率。这是一种空间换时间的做法。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
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》 这本书的介绍吧!