Ton*_*riz 2 objective-c dealloc ios automatic-ref-counting
我将保持这个简短明了:我有一个对象的dealloc方法被调用.我还每3秒调用一次NSTimer来记录控制所述对象的当前保留计数.
需要明确的是:我知道NSTimer将保留该对象.即使考虑到这一点,情况仍然没有加起来.
无论如何 - 在这个计时器触发时,对象的保留计数被记录为3.这让我感到困惑有两个原因:
任何帮助是极大的赞赏.谢谢.
编辑:代码:
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(logRetainCount) userInfo:nil repeats:YES];
Run Code Online (Sandbox Code Playgroud)
^在viewDidLoad中设置
- (void)logRetainCount
{
NSLog(@"own retain count: %ld", CFGetRetainCount((__bridge CFTypeRef)self));
}
Run Code Online (Sandbox Code Playgroud)
^日志保留计数的方法
- (void)dealloc {
NSLog(@"view controller deallocated");
}
Run Code Online (Sandbox Code Playgroud)
^ dealloc方法在VC中实现,应该被解除分配
和控制台输出:
自己保留计数:5
视图控制器已取消分配
自己保留计数:3
你问:
是否可以
dealloc在保留计数不为零的对象上调用?
由于您使用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
Run Code Online (Sandbox Code Playgroud)
当我推送到这个视图控制器时,我在控制台上看到以下内容:
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"按钮时,我们可以看到计时器仍然保持对它的强引用:
你问:
dealloc如果对象的保留计数未达到0,为什么被调用?
它不可能.因此,我们必须在此处涉及视图控制器的多个实例,一个具有未解除分配的重复计时器,另一个没有计时器,在解析其最后一个强引用时将解除分配.但无论target定时器是什么对象,它都会有一个强引用,直到定时器失效,并且在定时器invalidate被调用之前它不会被释放.
- 既然
dealloc被调用了,那么至少应该保留计数为1,因为NSTimer实例正在保持它?
不,当重复计时器正在触发时,其目标无法解除分配.我们必须讨论视图控制器的多个实例(或者,与上面的示例不同,target计时器不是视图控制器).
有很多方法可以意外地引入视图控制器的其他实例.对于一个随机的例子(我在Stack Overflow上不止一次看到过这个例子),考虑你在两个视图控制器之间做了一个segue,并prepareForSegue做了类似的事情:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SecondViewController *secondViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
secondViewController.property = @"foo";
}
Run Code Online (Sandbox Code Playgroud)
这是不正确的,因为除了segue实例化的视图控制器(the segue.destinationViewController)之外,上面prepareForSegue将创建另一个实例.创建的那个prepareForSegue一旦超出范围就会被释放,但是由于创建的重复计时器,segue创建的那个将不会被释放viewDidLoad.
我并不是说这就是你所做的,但它说明了一种可能的方式来获得你描述的行为.
但是,简而言之,不,在ARC中,仍然具有任何强引用的对象将不会被释放.仅当删除最后剩余的强引用时才会取消分配.您问题中的代码不能单独产生您描述的行为.您必须处理视图控制器的一些额外实例或类似的奇怪事情.我可能会建议您创建一个简单的示例来重现您描述的问题,因为您问题中的代码没有.还有其他事情要发生.
| 归档时间: |
|
| 查看次数: |
341 次 |
| 最近记录: |