问题分析

我看过很多文章关于在dispatch_async的block里面使用_weak self, 但是让我疑惑的是,以下代码是否需要必须使用_weak self, 因为我也看到了很多观点说,在有些情况下不需要使用__weak self.

self.myQueue = dispatch_queue_create("com.biview.core_data", NULL);

dispatch_async(self.myQueue, ^(void){
if(!self.var1){
self.var1 =
} dispatch_async(dispatch_get_main_queue(), ^(void){
if([self.var2 superview]) {
[self.var2 removeFromSuperview];
} [self.Label setText:text];
});
});复制代码

解析

针对上面的问题,我们假设:self是指向UIViewController的对象指针。
考虑以下几点:

  • UIViewController是"UIkit"对象,UIKit对象不应该在非主线程发送消息,也就是说,这些方法只能在主线程中执行。
  • 当一个block被添加进一个同步或者异步队列,这个block最终都会被执行,除非在执行到它之前应用程序被杀死。
  • 当block被拷贝的时候,strong类型的指针会被retained, 当block执行完毕之后被销毁的时候才会执行released操作。
  • weak类型的指针不会被retained和released。

在上面的例子中,self是在主线程的队列中,不必担心有任何bug产生。

究竟发生了什么?

当在dispatch的异步队列的block中捕获到self时,self会被执行retained操作,当block执行完毕后self执行released操作。
这意味着:当block执行完毕后,self的生命周期才会结束。上例中的第二个block是在主线程的队列中,它保证了self一直存活着当这个block被执行的时候。
在程序中存在潜在危险的操作是:延长 self 的生命周期。

如果你明确的不希望延长UIViewController对象的生命周期,而是当block被执行的时候去检查UIViewController对象到底是否存在,你可以使用 _weak self. 需要注意的是block最后都会被执行,不管UIViewController是否存活还是已经被释放了。

如果你希望如果UIViewController已经被释放了,那么block不做任何事情,可以写成 _weak self.

MyController * _weak weakSelf = self;
dispatch_async(queue, ^{
MyController *strongSelf = weakSelf;
if(strongSelf){
...
}else {
// self has been deallocted in the meantime.
}
});复制代码

不能在非主线程中向UIKit对象发送消息。
另一个细微的错误可能发生在UIKit对象执行方法在非主线程。

如果block在异步线程中捕获了一个UIKit对象,可能发生的是:block 是最后一个持有改UIKit的强引用。当block执行完的时候,UIKit对象将被release,因为是UIKit对象的最后一个强引用,所有该UIKit对象将被释放,但是,释放操作发生在block所执行的线程-它不是主线程,所有,风险即将发生,UIKit对象的dealloc方法将被调用(UI 对象应该在主线程中被回收,因为在它们的 dealloc 方法被调用回收的时候,可能会去改变 view 的结构关系,而如我们所知,这种操作应该放在主线程来进行,见参考二)。

避免这个错误:

UIViewController *strongUIKitPointer = ...
dispatch_async(non_main_queue), ^{
...//do someting
dispatch(dispatch_get_main_queue(),^{
[strongUIkitPointer self]; //self is a method, too -doing nothing.
});
});复制代码

举例

双向强引用发生在:一个强类型对象A持有一个强类型对象B,并且对象B强引用对象A。“Block”是一个强引用对象。

人为的双向强引用举例:

typedef void(^my_completion_block_t)(NSArray* result);

@interface UserViewController : UIViewController
@property (nonatomic, copy) my_completion_block_t completion;
@property (nonatomic) NSArray *users;复制代码

on "UserViewController.m"

self.completion = ^(NSArray *users){
self.users = users;
}
[self fetchUsers];复制代码

这是一个典型了强引用循环。UserViewController 有一个Block类型的属性,所有UserViewController对象强引用着block。而block捕获到self的时候执行强引用操作,所有形成了强引用循环。

解决方式:

  1. 使用_weak 指针指向self.

    UserViewController * _weak weakSelf = self;
    self.completion = ^(NSArray *user){
    UsersViewController *strongSelf = weakSelf;
    if(strongSelf){
    strongSelf.users = users;
    }else{
    // the view controller does not exist anymore.
    }
    };复制代码
  2. 使用block 指针执行self, 执行完毕后将block 指针指向nil.

    UsersViewController *__block blockSelf = self;
    self.completion=^(NSArayy *users){
    self.completion = ^(NSArray *users){
    blockSelf.users = users;
    blockSelf = nil;
    }
    }复制代码

--完--

参考

  1. stack overflow
  2. objc-cn

dispatch_async 的 block 中是否该使用_weak self的更多相关文章

  1. @weakify, @strongify ObjC的Block中使用weakSelf/strongSelf @weakify/@strongify

    首先要说说什么时候使用weakSelf和strongSelf. 下面引用一篇博客<到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf>的内容: Objec ...

  2. ObjC的Block中使用weakSelf/strongSelf @weakify/@strongify

    首先要说说什么时候使用weakSelf和strongSelf. 下面引用一篇博客<到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf>的内容: Objec ...

  3. iOS Block中的weakSelf/strongSelf

    Objective C 的 Block 是一个很实用的语法,特别是与GCD结合使用,可以很方便地实现并发.异步任务.但是,如果使用不当,Block 也会引起一些循环引用问题(retain cycle) ...

  4. 到底什么时候才需要在ObjC的Block中使用weakSelf/strongSelf

    转载,原文: http://blog.lessfun.com/blog/2014/11/22/when-should-use-weakself-and-strongself-in-objc-block ...

  5. iOS 中block中使用了外部变量的分析

    例子1: ; void (^blk)(void) = ^(){ printf("in block %d[%p]\n", val, &val); //in block 10[ ...

  6. block中如何避免循环引用

    使用 weak–strong dance 技术 block 可以直接引用 self,但是要非常小心地在 block 中引用 self.因为在 block 引用 self,可能会导致循环引用.如下例所示 ...

  7. ios 使用block中使用self可能产生的循环引用

    在block中调用 self,那么就会引起循环引用问题,那么这是为什么呢? 为什么self会对block进行强引用呢???? 这里推荐一篇关于block的专业文章,http://blog.csdn.n ...

  8. block中出现此种报错: Incompatible block pointer types initializing 'float (^__strong)(float, float)' with an expression of type 'int (^)(float, float)'

    当block(代码块)的返回值是float时,应注意的地方:定义的返回值类型一定要与return的返回值类型一样 我们以两个数的四则运算来举例 在main.m文件中的四则运算中,我采用两种返回值类型( ...

  9. Block中的引用循环

    原文地址:http://www.cnblogs.com/lujianwenance/p/5910490.html Block在实际的开发中非常的常用,事件回调.传值.封装成代码块调用等等.很多人都对b ...

随机推荐

  1. Spark Streaming 编程入门指南

    Spark Streaming 是核心Spark API的扩展,可实现实时数据流的可伸缩,高吞吐量,容错流处理.可以从许多数据源(例如Kafka,Flume,Kinesis或TCP sockets)中 ...

  2. MySQl 和 Redis

    MySQL MySQL 是关系型数据库,开放源码软件,主要使用持久化存储设备(像磁盘)数据存放在磁盘中,功能强大. 因为磁盘访问速度远远慢于内存,所以访问速度慢 Redis 是非关系型,高性能的key ...

  3. zendframework3

    1.开发时关闭cache,正式上线后打开cache application config file (config/application.config.php),  disable this cac ...

  4. 2016蓝桥杯报纸页数(C++C组)

    题目: 报纸页数X星球日报和我们地球的城市早报是一样的,都是一些单独的纸张叠在一起而已.每张纸印有4版.比如,某张报纸包含的4页是:5,6,11,12,可以确定它应该是最上边的第2张报纸.我们在太空中 ...

  5. 10.2 io流 之字节流和字符流

    FileWriter 用于写入字符流.要写入原始字节流,请考虑使用 FileOutputStream. io流相关文档: https://www.cnblogs.com/albertrui/p/836 ...

  6. 在java 中一种简单方式的声明静态Map常量的方法

    我现在需要在一个类里面放一个HashMap,往里面放一些数据,每次要从数据库中取数据的时候先查找HashMap,看是否已经存在,若存在就直接提取,若不存在就从数据库中抽取数据之后再放到HashMap中 ...

  7. not found 什么时候触发

    eq: BEGIN        DECLARE EXIT HANDLER FOR NOT FOUND SET o_state = 999;         select count(1) into ...

  8. Xray安装与使用

    0×00 Xray简介 xray是从长亭洞鉴核心引擎中提取出的社区版漏洞扫描神器,支持主动.被动多种扫描方式,自备盲打平台.可以灵活定义 POC,功能丰富,调用简单,支持 Windows / macO ...

  9. 【Canvas】(2)---绘制折线图

    绘制折线图 之前在工作的时候,用过百度的ECharts绘制折线图,上手很简单,这里通过canvas绘制一个简单的折线图.这里将一整个绘制过程分为几个步骤: 1.绘制网格 2.绘制坐标系 3.绘制点 4 ...

  10. 疲劳驾驶打瞌睡?python保障您的驾驶安全

    道路千万条,安全第一条!疲劳驾驶可谓交通事故几大罪魁祸首之一,根据美国一项研究显示,司机睡眠不足4小时,交通事故肇事几率等同于醉驾. 为了减少疲劳驾驶现象,驾驶员疲劳检测应运而生.这是一项安全技术,可 ...