iOS-block多线程GCD 队列 异步 网络 socket block 循环引用iOS进阶相关

iOS - 深入探究Block循环引用

2015-10-09  本文已影响4523人  Mitchell
作者:Mitchell 

一、根据需求提出问题

 - (void)viewDidLoad {
    [super viewDidLoad];
    MitPerson*person = [[MitPerson alloc]init];
    __weak MitPerson * weakPerson = person;
    person.mitBlock = ^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [weakPerson test];
        });
    };
    person.mitBlock();
}

直接运行这段代码会发现[weakPerson test];并没有执行,打印一下会发现,weakPerson 已经是 Nil 了,这是由于当我们的 viewDidLoad 方法运行结束,由于是局部变量,无论是 MitPerson 和 weakPerson 都会被释放掉,那么这个时候在 Block 中就无法拿到正真的 person 内容了。

 - (void)viewDidLoad {
    [super viewDidLoad];
    MitPerson*person = [[MitPerson alloc]init];
    __weak MitPerson * weakPerson = person;
    person.mitBlock = ^{
        __strong MitPerson * strongPerson = weakPerson;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [strongPerson test];
        });
    };
    person.mitBlock();
}

这样当2秒过后,计时器依然能够拿到想要的 person 对象。

二、深入探究原理

1、开辟一段控件存储 person 类对象内容,创建 person 强指针。
 MitPerson*person = [[MitPerson alloc]init];
2、创建一个弱指针 weakPerson 指向person对象内容 
 __weak MitPerson * weakPerson = person;
  person.mitBlock = ^{
  3、在 person 对象的 Block 内部创建一个强指针来指向 person 对象,为了保证当计时器执行代码的时候,person 对象没有被系统销毁所以我们必须在系统内部进行一次强引用,并用 GCD 计时器引用 strongPerson,为了保留 person 对象,在下面会对这里更加详细的说明。
    __strong MitPerson * strongPerson = weakPerson;
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
          [strongPerson test];
      });
  };
4、执行 Block 代码
    person.mitBlock();
  person.mitBlock = ^{
 __strong MitPerson * strongPerson = weakPerson;
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
          [strongPerson test];
      });
  };

上一篇下一篇

猜你喜欢

热点阅读