IOS后台线程更新UI的一个陷阱
来源:互联网 发布:软件无线电原理 编辑:程序博客网 时间:2024/06/08 20:07
先看代码
这是一段异步下载图片并更新UI的代码
- @interface GXAlertView : UIView {
- @private
- UIImageView *_imageView;
- UIActivityIndicatorView *_indicatorView;
- }
- - (void)asyncLoadUrl:(NSString *)aUrl
- {
- NSURL *imageURL = [NSURL URLWithString:aUrl];
- [imageURL retain];
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
- dispatch_async(queue, ^{
- NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
- [imageURL release];
- [imageData retain];
- dispatch_sync(dispatch_get_main_queue(), ^{
- if (imageData) {
- _imageView.image = [UIImage imageWithData:imageData];
- [imageData release];
- }
- [_indicatorView stopAnimating];
- [_indicatorView removeFromSuperview];
- [_indicatorView release];
- _indicatorView = nil;
- });
- });
- }
跑一下看看也正常,不过,你要是就以为ok了,那就麻烦了。
崩溃了!!!!
XCode永远停在了XXXView的dealloc里,这是为什么呢?看下调用栈就明白了。没有想到啊,果然是在后台线程的block成了压垮了GXAlertView某个对象的最后一根稻草(retainCount == 0)。至于为什么crash, log说得很清楚
怎么办
解决办法很直接,别访问self就行了(访问实例成员变量和函数会隐含访问self)
- - (void)asyncLoadUrl:(NSString *)aUrl
- {
- NSURL *imageURL = [NSURL URLWithString:aUrl];
- [imageURL retain];
- // changes. here
- UIImageView *imageView = [_imageView retain];
- UIActivityIndicatorView *indicatorView = [_indicatorView retain];
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
- dispatch_async(queue, ^{
- NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
- [imageURL release];
- [imageData retain];
- dispatch_sync(dispatch_get_main_queue(), ^{
- if (imageData) {
- imageView.image = [UIImage imageWithData:imageData];
- [imageData release];
- }
- [indicatorView stopAnimating];
- [indicatorView removeFromSuperview];
- [indicatorView release];
- [imageView release];
- });
- });
- }
小结
block访问self会增加self的引用计数。
所以的UIKit操作都最好都放到主线程去。
release view也算访问UIKit。
在后台线程直接访问UIKit太危险。
- IOS后台线程更新UI的一个陷阱
- IOS后台线程更新UI的一个陷阱
- android后台线程更新UI
- c#中后台线程更新主线程ui的方法
- .NET中 后台子线程 更新UI
- UWP(3) 后台线程如何更新UI
- 后台线程更新DataGridView数据的一个异常更改
- iOS子线程更新UI的两种方法
- iOS子线程更新UI的两种方法
- iOS子线程更新UI的两种方法
- 一个通过线程更新UI的例子(利用message)
- 一个奇怪的子线程更新UI问题
- 后台线程与UI线程的交互
- AndroidUI——后台线程更新UI的几种方式
- Handler后台异步更新UI的总结
- .NET一个线程更新另一个线程的UI(两种实现方法及若干简化)
- .NET一个线程更新另一个线程的UI(两种实现方法及若干简化)
- C#后台线程和UI的交互
- opencv查找轮廓---cvFindContours && cvDrawCountours 用法及例子
- C++类构造函数初始化列表
- 标准程序流程图的符号及使用约定
- Factory模式与Prototype模式的异同
- VB的内存释放(鄙视那些说内存泄露的人,适用VB6,.NET)
- IOS后台线程更新UI的一个陷阱
- C语言编译的顺序。关于 .c 文件 .h 文件的用法。Makefile文件简单概念。
- 二叉排序树转换成双向链表
- VC调用DLL
- 拓扑排序模板(备忘之用)
- 《C++ Primer》 第02章 [ 变量和基本类型 ]
- HDU1788 水题
- poj 1094 topsort
- AE 遍历栅格实现栅格重分类(C#实现)