是否可以在保留计数不为零的对象上调用 dealloc?
Is it possible for dealloc to be called on an object whose retain count is NOT zero?
我将保持简短明了:我有一个正在调用其 dealloc 方法的对象。我还有一个 NSTimer 每 3 秒被调用一次以记录以控制所述对象的当前保留计数。
明确一点:我知道 NSTimer 会保留对象。这么一想,情况还是不对。
无论如何 - 在这个计时器触发时,对象的保留计数被记录为 3。这让我感到困惑有两个原因:
- 如果对象的保留计数从未达到 0,为什么要调用 dealloc?
- 既然 dealloc 被调用,至少,保留计数不应该是 1,因为 NSTimer 实例正在持有它?
非常感谢任何帮助。谢谢。
编辑:代码:
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(logRetainCount) userInfo:nil repeats:YES];
^ 在 viewDidLoad 中设置
- (void)logRetainCount
{
NSLog(@"own retain count: %ld", CFGetRetainCount((__bridge CFTypeRef)self));
}
^ 日志保留计数的方法
- (void)dealloc {
NSLog(@"view controller deallocated");
}
^ dealloc 方法在 VC 中实现,应该被释放
控制台输出:
own retain count: 5
view controller deallocated
own retain count: 3
你问:
Is it possible for dealloc
to be called on an object whose retain count is NOT zero?
由于您使用的是 ARC,我们不再在该上下文中使用 "retain count"。但是在回答你的问题时,不,在有强引用的情况下不能释放对象。当您调用 scheduledTimerWithTimeInterval
时,如果这是一个重复计时器,它将保持对 target
的强引用,防止目标被释放(至少在调用计时器的 invalidate
之前) .
考虑:
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(logRetainCount) userInfo:nil repeats:YES];
}
- (void)logRetainCount {
NSLog(@"own retain count: %ld", CFGetRetainCount((__bridge CFTypeRef)self));
}
- (void)dealloc {
NSLog(@"view controller deallocated");
}
@end
当我推送到这个视图控制器时,我在控制台上看到以下内容:
2016-09-15 15:50:10.279 MyApp[7777:159811] own retain count: 3
2016-09-15 15:50:13.340 MyApp[7777:159811] own retain count: 3
当我关闭视图控制器时,我看到:
2016-09-15 15:50:16.338 MyApp[7777:159811] own retain count: 2
2016-09-15 15:50:19.270 MyApp[7777:159811] own retain count: 2
请注意,我们不会看到 "view controller deallocated" 出现在控制台中。
当我点击 Xcode 8 的 "Debug Memory Graph" 按钮时,我们可以看到计时器仍然保持对它的强引用:
你问:
- Why is
dealloc
being called if the object's retain count is not ever reaching 0?
不可能。因此,我们必须在此处涉及多个视图控制器实例,一个具有未释放的重复计时器,另一个没有计时器,在其最后一个强引用被解析时被释放。但是,无论对象是定时器的 target
,在定时器失效之前,它仍然具有对它的强引用,并且在定时器调用其 invalidate
之前,它不会被释放。
- Since
dealloc
is getting called, shouldn't, at the very least, the retain count be 1 since the NSTimer
instance is holding onto it?
不,当重复计时器触发时,它的目标不能被释放。我们必须讨论视图控制器的多个实例(或者,与上面的示例不同,计时器的 target
不是视图控制器)。
有很多方法可以不小心引入视图控制器的额外实例。举一个随机的例子(我在 Stack Overflow 上不止一次看到过),假设你在两个视图控制器之间做了一个 segue,并且有一个 prepareForSegue
做了类似的事情:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
secondViewController.property = @"foo";
}
这是不正确的,因为除了 segue 实例化的视图控制器(segue.destinationViewController
)之外,上面的 prepareForSegue
将创建另一个实例。在 prepareForSegue
中创建的那个一旦超出范围就会被释放,但是由 segue 创建的那个不会被释放,因为在 viewDidLoad
.[=34 中创建了重复计时器=]
我并不是说这就是你所做的,但它说明了一种可能的方式来获得你所描述的行为。
但是,简而言之,不,在 ARC 中,一个仍然有任何强引用的对象将不会被释放。只有当最后一个剩余的强引用被移除时,它才会被释放。您问题中的代码不能单独产生您描述的行为。您必须处理一些额外的视图控制器实例或类似的好奇。我可能建议您创建一个 simple example 来重现您描述的问题,因为您问题中的代码没有。还有其他事情。
我将保持简短明了:我有一个正在调用其 dealloc 方法的对象。我还有一个 NSTimer 每 3 秒被调用一次以记录以控制所述对象的当前保留计数。
明确一点:我知道 NSTimer 会保留对象。这么一想,情况还是不对。
无论如何 - 在这个计时器触发时,对象的保留计数被记录为 3。这让我感到困惑有两个原因:
- 如果对象的保留计数从未达到 0,为什么要调用 dealloc?
- 既然 dealloc 被调用,至少,保留计数不应该是 1,因为 NSTimer 实例正在持有它?
非常感谢任何帮助。谢谢。
编辑:代码:
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(logRetainCount) userInfo:nil repeats:YES];
^ 在 viewDidLoad 中设置
- (void)logRetainCount
{
NSLog(@"own retain count: %ld", CFGetRetainCount((__bridge CFTypeRef)self));
}
^ 日志保留计数的方法
- (void)dealloc {
NSLog(@"view controller deallocated");
}
^ dealloc 方法在 VC 中实现,应该被释放
控制台输出:
own retain count: 5
view controller deallocated
own retain count: 3
你问:
Is it possible for
dealloc
to be called on an object whose retain count is NOT zero?
由于您使用的是 ARC,我们不再在该上下文中使用 "retain count"。但是在回答你的问题时,不,在有强引用的情况下不能释放对象。当您调用 scheduledTimerWithTimeInterval
时,如果这是一个重复计时器,它将保持对 target
的强引用,防止目标被释放(至少在调用计时器的 invalidate
之前) .
考虑:
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(logRetainCount) userInfo:nil repeats:YES];
}
- (void)logRetainCount {
NSLog(@"own retain count: %ld", CFGetRetainCount((__bridge CFTypeRef)self));
}
- (void)dealloc {
NSLog(@"view controller deallocated");
}
@end
当我推送到这个视图控制器时,我在控制台上看到以下内容:
2016-09-15 15:50:10.279 MyApp[7777:159811] own retain count: 3 2016-09-15 15:50:13.340 MyApp[7777:159811] own retain count: 3
当我关闭视图控制器时,我看到:
2016-09-15 15:50:16.338 MyApp[7777:159811] own retain count: 2 2016-09-15 15:50:19.270 MyApp[7777:159811] own retain count: 2
请注意,我们不会看到 "view controller deallocated" 出现在控制台中。
当我点击 Xcode 8 的 "Debug Memory Graph" 按钮时,我们可以看到计时器仍然保持对它的强引用:
你问:
- Why is
dealloc
being called if the object's retain count is not ever reaching 0?
不可能。因此,我们必须在此处涉及多个视图控制器实例,一个具有未释放的重复计时器,另一个没有计时器,在其最后一个强引用被解析时被释放。但是,无论对象是定时器的 target
,在定时器失效之前,它仍然具有对它的强引用,并且在定时器调用其 invalidate
之前,它不会被释放。
- Since
dealloc
is getting called, shouldn't, at the very least, the retain count be 1 since theNSTimer
instance is holding onto it?
不,当重复计时器触发时,它的目标不能被释放。我们必须讨论视图控制器的多个实例(或者,与上面的示例不同,计时器的 target
不是视图控制器)。
有很多方法可以不小心引入视图控制器的额外实例。举一个随机的例子(我在 Stack Overflow 上不止一次看到过),假设你在两个视图控制器之间做了一个 segue,并且有一个 prepareForSegue
做了类似的事情:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
secondViewController.property = @"foo";
}
这是不正确的,因为除了 segue 实例化的视图控制器(segue.destinationViewController
)之外,上面的 prepareForSegue
将创建另一个实例。在 prepareForSegue
中创建的那个一旦超出范围就会被释放,但是由 segue 创建的那个不会被释放,因为在 viewDidLoad
.[=34 中创建了重复计时器=]
我并不是说这就是你所做的,但它说明了一种可能的方式来获得你所描述的行为。
但是,简而言之,不,在 ARC 中,一个仍然有任何强引用的对象将不会被释放。只有当最后一个剩余的强引用被移除时,它才会被释放。您问题中的代码不能单独产生您描述的行为。您必须处理一些额外的视图控制器实例或类似的好奇。我可能建议您创建一个 simple example 来重现您描述的问题,因为您问题中的代码没有。还有其他事情。