1、循环引用

创建一个Person类,添加一个block属性,在block内部访问peron对象:

  1. {
  2. Person *person = [[Person alloc] init];
  3. person.block = ^{
  4. NSLog(@"person = %p", person);
  5. };
  6. }

这段代码会导致person对象和block无法释放,原因是block捕获了person对象,内部会强引用person对象,而person对象也强引用着block,造成了相互循环引用,导致无法释放。
image.png

2、ARC环境解决block循环引用

2.1、用__weak解决(推荐)

block内存管理可知,内部捕获的对象类型变量,引用方式会根据指向对象指针的修饰符决定,所以外部用weak修饰person,block内部也会弱引用person对象。

  1. {
  2. Person *person = [[Person alloc] init];
  3. __weak typeof(person) weakPerson = person;
  4. person.block = ^{
  5. NSLog(@"person = %p", weakPerson);
  6. };
  7. }

image.png

2.2、用__block解决(不推荐)

用block修饰person对象后,在block内部就可以修改person的值,只要将内部的person指针置为nil,就可以解决循环引用,但是必须等到block执行才可以,而且置为nil后person不能再继续使用。

  1. __block Person *person = [[Person alloc] init];
  2. NSLog(@"1 person = %p", person);
  3. person.block = ^{
  4. NSLog(@"person = %p", person);
  5. person = nil;
  6. };
  7. person.block();

image.png

3、MRC环境下解决block循环引用

3.1、用__unsafe_unretained解决

MRC环境下不支持weak(弱引用)的,所以可以使用unsafe_unretained解决,__unsafe_unretained不会在block内部进行retain操作。

  1. {
  2. Person *person = [[Person alloc] init];
  3. __unsafe_unretained typeof(person) weakPerson = person;
  4. person.block = ^{
  5. NSLog(@"person = %p", person);
  6. };
  7. }

3.2、用__block解决

在MRC环境下block捕获的对象变量都不会retain,所以使用block修饰可以解决循环引用。

  1. {
  2. __block Person *person = [[Person alloc] init];
  3. person.block = ^{
  4. NSLog(@"person = %p", person);
  5. };
  6. }