iOS - GCD 对自身的弱引用和强引用
iOS - GCD weak and strong reference to self
当我在 GCD
的一个区块中时,我总是使用 __weak
引用 self
。每个人都建议这样做。我知道在 GCD 中对 self
(已测试)的强引用不能产生保留周期。
Apple 建议使用 __weak
对自身的引用,然后 __strong
对 _week
引用的引用,以保证 self
不会执行块时 nil
。
我有如下一段代码:
- (IBAction)startGCD:(id)sender {
GCDVC* __weak weakSelf = self;
[self.activityIndicator startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // 1
// VC2* __strong strongSelf = weakSelf;
[weakSelf.proArray addObject:@"2"];
[NSThread sleepForTimeInterval:10];
NSLog(@"%@",weakSelf.proArray);
dispatch_async(dispatch_get_main_queue(), ^{ // 2
[weakSelf.activityIndicator stopAnimating];
});
});
}
测试 1
我按下按钮,指示器开始旋转。我在 GCD 完成之前按下后退按钮,GCDViewController 被释放。
测试 2
然后我取消对 self 的强引用的注释并执行相同的过程。 GCDViewController 在块完成工作之前不会被释放。但后来发布了。
测试 3
现在,如果我直接引用 self(没有 __weak
或 __strong
),我的行为与测试 2 完全相同。
因此,如果我想确保在执行块时 self 不会为 nil,那么使用 __strong
引用 __weak
引用 [=13= 的意义何在? ]?我在这里想念什么吗?是否有任何示例会改变测试 2 和 3 的结果?
I was always using __weak references to self when I was in a block in
GCD. Everyone recommends that.
没有。我不知道有谁推荐这个。在某些存在循环保留的情况下,弱引用是有意义的。但是一个块是否应该捕获对任何对象(包括 self
指向的对象)的弱引用或强引用取决于相关代码的特定内存管理设计和
I know that strong reference to self (tested) in GCD can't produce
retain cycles.
在全局或主队列上将块传递给 dispatch_async
永远不会产生保留周期。
Now if I refer directly to self (without __weak or __strong) I have
the exact behaviour with Test 2.
在这种情况下,您可能看不出有什么不同。但它们通常有不同的行为。基本上,您的问题是捕获对 self
.
指向的对象的强引用或弱引用的块之间有什么区别
不同之处在于,如果当前对象(self
指向的对象)已被持有强引用的所有其他对象释放,除了潜在的块和块之后异步执行。
- 如果该块捕获了对当前对象的强引用,那么该引用将使该对象在整个时间内保持活动状态。所以对象仍然存在,我们可以使用它并向它发送消息等。
- 如果块捕获了对当前对象的弱引用,那么当前对象已经被释放,当对它的最后一个强引用被释放时。所以这个块的弱引用在这一点上是
nil
,并且这个块不会对它做任何事情(它要么在看到它时检查 strongSelf
和 return是 nil
,否则它将向 strongSelf
发送消息,即 nil
什么都不做)。
所以在一种情况下,事情已经完成,而在另一种情况下,什么也没做。
如果您的当前对象是某个 UI 元素,例如视图或视图控制器,那么只要它在视图层次结构中,它就会被视图中的事物保留层次结构,所以你需要退出这个 view/view 控制器,以便没有其他东西对它有强引用。
在你的情况下,你在块内所做的就是 [weakSelf.activityIndicator stopAnimating];
,即对 UI 的更改。这个命令是不是运行并不重要,因为,记住,包含这个的视图已经停止显示了。没有人可以看到这个 activity 指标。那么停不停有什么区别呢?但这是特定于这种情况的。一般来说,你可以想象块内的命令改变一些全局状态,或者通过网络发送一些东西什么的,做与不做之间有很大的区别。
当我在 GCD
的一个区块中时,我总是使用 __weak
引用 self
。每个人都建议这样做。我知道在 GCD 中对 self
(已测试)的强引用不能产生保留周期。
Apple 建议使用 __weak
对自身的引用,然后 __strong
对 _week
引用的引用,以保证 self
不会执行块时 nil
。
我有如下一段代码:
- (IBAction)startGCD:(id)sender {
GCDVC* __weak weakSelf = self;
[self.activityIndicator startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ // 1
// VC2* __strong strongSelf = weakSelf;
[weakSelf.proArray addObject:@"2"];
[NSThread sleepForTimeInterval:10];
NSLog(@"%@",weakSelf.proArray);
dispatch_async(dispatch_get_main_queue(), ^{ // 2
[weakSelf.activityIndicator stopAnimating];
});
});
}
测试 1 我按下按钮,指示器开始旋转。我在 GCD 完成之前按下后退按钮,GCDViewController 被释放。
测试 2 然后我取消对 self 的强引用的注释并执行相同的过程。 GCDViewController 在块完成工作之前不会被释放。但后来发布了。
测试 3
现在,如果我直接引用 self(没有 __weak
或 __strong
),我的行为与测试 2 完全相同。
因此,如果我想确保在执行块时 self 不会为 nil,那么使用 __strong
引用 __weak
引用 [=13= 的意义何在? ]?我在这里想念什么吗?是否有任何示例会改变测试 2 和 3 的结果?
I was always using __weak references to self when I was in a block in GCD. Everyone recommends that.
没有。我不知道有谁推荐这个。在某些存在循环保留的情况下,弱引用是有意义的。但是一个块是否应该捕获对任何对象(包括 self
指向的对象)的弱引用或强引用取决于相关代码的特定内存管理设计和
I know that strong reference to self (tested) in GCD can't produce retain cycles.
在全局或主队列上将块传递给 dispatch_async
永远不会产生保留周期。
Now if I refer directly to self (without __weak or __strong) I have the exact behaviour with Test 2.
在这种情况下,您可能看不出有什么不同。但它们通常有不同的行为。基本上,您的问题是捕获对 self
.
不同之处在于,如果当前对象(self
指向的对象)已被持有强引用的所有其他对象释放,除了潜在的块和块之后异步执行。
- 如果该块捕获了对当前对象的强引用,那么该引用将使该对象在整个时间内保持活动状态。所以对象仍然存在,我们可以使用它并向它发送消息等。
- 如果块捕获了对当前对象的弱引用,那么当前对象已经被释放,当对它的最后一个强引用被释放时。所以这个块的弱引用在这一点上是
nil
,并且这个块不会对它做任何事情(它要么在看到它时检查strongSelf
和 return是nil
,否则它将向strongSelf
发送消息,即nil
什么都不做)。
所以在一种情况下,事情已经完成,而在另一种情况下,什么也没做。
如果您的当前对象是某个 UI 元素,例如视图或视图控制器,那么只要它在视图层次结构中,它就会被视图中的事物保留层次结构,所以你需要退出这个 view/view 控制器,以便没有其他东西对它有强引用。
在你的情况下,你在块内所做的就是 [weakSelf.activityIndicator stopAnimating];
,即对 UI 的更改。这个命令是不是运行并不重要,因为,记住,包含这个的视图已经停止显示了。没有人可以看到这个 activity 指标。那么停不停有什么区别呢?但这是特定于这种情况的。一般来说,你可以想象块内的命令改变一些全局状态,或者通过网络发送一些东西什么的,做与不做之间有很大的区别。