ios - 是否可以在保留计数不为零的对象上调用 dealloc?

标签 ios objective-c automatic-ref-counting dealloc

我会保持简短和明显:我有一个正在调用其 dealloc 方法的对象。我还每 3 秒调用一次 NSTimer 来记录以控制台所述对象的当前保留计数。

需要明确的是:我知道 NSTimer 将保留该对象。即使考虑到这一点,情况仍然不合理。

无论如何 - 当这个计时器触发时,对象的保留计数被记录为 3。这让我困惑有两个原因:

  1. 如果对象的保留计数从未达到 0,为什么要调用 dealloc?
  2. 既然 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");
}

^ VC 中实现的 dealloc 方法应该被释放

控制台输出:

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,我们不再在该上下文中使用“保留计数”。但回答你的问题时,不,当存在强引用时,对象不能被释放。当您调用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

当我推送到此 View Controller 时,我在控制台上看到以下内容:

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

And when I pop that view controller off, I see:

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

Note, we do not see "view controller deallocated" appear in the console.

When I click on Xcode 8's "Debug Memory Graph" button, we can see that the timer is still keeping a strong reference to it:

timer

You ask:

  1. Why is dealloc being called if the object's retain count is not ever reaching 0?

It can't be. So, we must have multiple instances of the view controller involved here, one that has the repeating timer that isn't deallocated, and one without the timer, that is deallocated when its last strong reference is resolved. But whatever object is the target of the timer will still have a strong reference to it until the timer is invalidated, and it will not be deallocated until the timer has its invalidate called.

  1. Since dealloc is getting called, shouldn't, at the very least, the retain count be 1 since the NSTimer instance is holding onto it?

No, while the repeating timer is firing, its target cannot be deallocated. We must be talking about multiple instances of the view controller (or, unlike the example above, the target of the timer wasn't the view controller).

There are lots of ways to accidentally introduce additional instances of a view controller. For a random example (one that I've seen here on Stack Overflow more than once), consider that you did a segue between two view controllers, and had a prepareForSegue that did something like:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
    secondViewController.property = @"foo";
}

这是不正确的,因为除了 segue 实例化的 View Controller ( segue.destinationViewController )之外,上面的 prepareForSegue将创建另一个实例。创建于 prepareForSegue一旦超出范围就会被释放,但是由 segue 创建的定时器不会被释放,因为 viewDidLoad 中创建了重复计时器。 .

我并不是说这就是您所做的,但它说明了获得您所描述的行为的一种可能方法。

但是,简而言之,不,在 ARC 中,仍然具有强引用的对象将不会被释放。只有当最后一个剩余的强引用被删除时,它才会被释放。您问题中的代码不能单独产生您所描述的行为。您必须处理 View Controller 的一些附加实例或类似的奇怪的东西。我可能建议您创建一个 simple example这会重现您所描述的问题,因为您问题中的代码不会重现您所描述的问题。还有其他事情正在发生。

关于ios - 是否可以在保留计数不为零的对象上调用 dealloc?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39520663/

相关文章:

objective-c - "float_t"是做什么用的?

objective-c - 这些对象什么时候在 ARC 下被释放?

iPhone Facebook 请求错误

ios - 带有 Cordova 垂直滚动的 Framework7 在 iOS 上不起作用

objective-c - OpenGL ES 在移动背景时崩溃,iOS 5.1

ios - 如何更改 UIAlertAction 的标题

ios - 当搜索栏打开/关闭时隐藏/显示导航栏上的后退按钮

ios - 将数据从 2 个 View Controller 发送到一个 View Controller

iphone - 为什么我应该更喜欢 __unsafe_unretained 限定符而不是为弱引用属性分配?

ios - 从后台返回后崩溃