Featured image of post 关于 weakSelf 和 strongSelf

关于 weakSelf 和 strongSelf

配图:https://www.freepik.com/free-vector/opposite-adjective-with-strong-weak_1172827.htm

关于 weakSelf 和 strongSelf

block 带来了一定程度的便利性,在作为回调使用时,时常会遇到内存问题,即「引用循环」,这在 Objc 中是一个绕不开的话题。

试着看如下场景:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
DemoViewController.m

- (void)viewDidLoad {
 	[super viewDidLoad];
	CustomView *v = [[CustomView alloc] init];
	[self.view addSubview:v];
	v.callbackBlock = ^{
		[self doSomething];
	}
}

viewDidLoad 方法执行时,创建一个 block 并赋值给对象 vcallbackBlock 属性,callbackBlock 捕捉 selfself 持有 self.view, v 在 addSubview 后成为 self.view 的子 view 而被 self.view 持有,这样就形成了一个引用循环,如下:

而如果 CustomView 对象不被创建时,不会造成引用循环:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
DemoViewController.m

- (void)viewDidLoad {
	[super viewDidLoad];
}

- (void)setup {
	CustomView *v = [[CustomView alloc] init];
	[self.view addSubview:v];
	v.callbackBlock = ^{
		[self doSomething];
	}
}

我们可以打破这个循环

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
DemoViewController.m

- (void)viewDidLoad {
 	[super viewDidLoad];
	CustomView *v = [[CustomView alloc] init];
	[self.view addSubview:v];
	__weak __typeof__(self) weakSelf = self;
	v.callbackBlock = ^{
		[weakSelf doSomething];
	}
}

callbackBlock 不直接引用 self,影响 self 的释放,由此打破循环,所有对象可以正常释放。

而当下面情况出现时,行为开始变得奇怪起来:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
DemoViewController.m

- (void)viewDidLoad {
 	[super viewDidLoad];
	CustomView *v = [[CustomView alloc] init];
	[self.view addSubview:v];
	__weak __typeof__(self) weakSelf = self;
	v.callbackBlock = ^{
		[weakSelf doSomething];
		[weakSelf doAnoterThing];
	}
}

callbackBlock 开始执行时,DemoViewController 对象已经释放,callbackBlockweakSelf 始终为 nil,不会造成什么影响,若在 callbackBlock 开始执行时 DemoViewController 对象还存在,在 doSomething 时,weakSelf 一定不为 nil,而在 doAnoterThing 时就不一定了,我项目中出现复杂的场景时会造成 callbackBlock 执行行为不一致,导致一些奇怪的问题,这个时候我可以利用引用计数的特性来解决,方案变成了下面:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
DemoViewController.m

- (void)viewDidLoad {
 	[super viewDidLoad];
	CustomView *v = [[CustomView alloc] init];
	[self.view addSubview:v];
	__weak __typeof__(self) weakSelf = self;
	v.callbackBlock = ^{
		__typeof__(self) strongSelf = weakSelf;
		[strongSelf doSomething];
		[strongSelf doAnoterThing];
	}
}

callbackBlock 开始执行时,产生一个对 weakSelf 的强引用,这样在 callbackBlock 的作用域范围内,self 不可能被释放,这样 callbackBlock 的执行行为在所有情况下是一致的,避免产生一些奇怪的问题。

那么如果 block 出现嵌套呢?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
DemoViewController.m

- (void)viewDidLoad {
 	[super viewDidLoad];
	CustomView *v = [[CustomView alloc] init];
	[self.view addSubview:v];
	__weak __typeof__(self) weakSelf = self;
	v.callbackBlock = ^{
		__typeof__(self) strongSelf = weakSelf;
		[strongSelf doSomething];
		[strongSelf doAnoterThing];
		obj.objCallbackBlock = ^{
			[strongSelf doObjSomething];
			[strongSelf doObjAnotherThing];
		}
	}
}

objCallbackBlock 捕捉的是 strongSelf,而 strongSelf 实际上还是指向对 self 的弱引用,strongSelf 可以保证在 callbackBlock 执行期间不释放,但是在 objCallbackBlock 执行期间并不能保证一定存在,所以还是会有执行不一致问题,所以在 objCallbackBlock 中再次对 weakSelf 进行一次强引用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
DemoViewController.m

- (void)viewDidLoad {
 	[super viewDidLoad];
	CustomView *v = [[CustomView alloc] init];
	[self.view addSubview:v];
	__weak __typeof__(self) weakSelf = self;
	v.callbackBlock = ^{
		__typeof__(self) strongSelf = weakSelf;
		[strongSelf doSomething];
		[strongSelf doAnoterThing];
		obj.objCallbackBlock = ^{
			__typeof__(self) strongSelf = weakSelf;
			[strongSelf doObjSomething];
			[strongSelf doObjAnotherThing];
		}
	}
}

以保证所有 block 的执行行为一致。

参考资料

Licensed under CC BY-NC-SA 4.0
Built with Hugo
主题 StackJimmy 设计