Du's Time

weak-strong dance的另外一种解释

Word count: 471 / Reading time: 2 min
2016/07/01 Share

以下是一个标准的weak-strong dance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
MyViewController *myController = [[MyViewController alloc] init];
// ...
MyViewController * __weak weakMyController = myController;
myController.completionHandler = ^(NSInteger result) {
MyViewController *strongMyController = weakMyController;
if (strongMyController) {
// ...
[strongMyController dismissViewControllerAnimated:YES completion:nil];
// ...
}
else {
// Probably nothing...
}
};

其中所有权修饰符变化过程为

1
初始化时为strong->调用block前转换为weak->在block中又转换为strong

Google搜出来的大部分博客将这两次修饰符转换的原因解释为:

  1. strong->weak:在自己里强引用自己会造成循环引用,因此需要声明一个weak变量供block内使用
  2. weak->strong:因为变量对内存对象是弱引用,因此在block执行的内存对象有可能被释放,因此需要声明一个strong的临时变量,保证在block过程中weak所指向的内存不会被释放

对于第二点我有些异议。在weak变量调用的过程中,ARC会自动生成一个autorelease的临时变量指向weak所在内存,防止在使用weak变量的过程中其指向的内存区域被释放,因此在block中并不需要担心weak指向的内存被释放,以上第二点的说法并不能成立。
以上观点我们可以在使用weak变量时打印AutoreleasePool的状态来证明。

1
以下打出AutoreleasePool

将OC文件改写成C++,clang -rewrite-objc

1
以下打出C++代码

那这时还需不需要使用strong临时变量呢?其实还是需要的。正因为weak在使用的过程中会不断生成autorelease变量,这会产生一定的性能开销,如果这时再声明一个strong变量,并在之后都使用这个strong变量,就避免了调用weak变量会附带生成autorelease变量问题。我想这个才是weak-strong中第二步的真正作用。

参考资料:
《Objective-C高级编程》

CATALOG