【问题标题】:How come retainCount not zero before dealloc gets called?为什么在调用 dealloc 之前 retainCount 不为零?
【发布时间】:2013-03-31 00:34:06
【问题描述】:

我正在尝试更深入地了解保留释放。这是我的代码,然后我将发布代码运行的输出。我不确定为什么当为'self'调用dealloc时保留计数永远不会为零。

其次,当我为其分配内存时,为什么 self.testNumber 的保留计数为 2,我应该使用“弱”属性来代替测试编号吗?

代码:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    _testNumber = [[NSNumber alloc] initWithInt:10];
    testNumber = [[NSNumber alloc] initWithInt:102];
    _testInt = 105;
    self.testNumber = [[NSNumber alloc] initWithInt:101];
    NSLog(@"self.testNumber retain count = %d",[self.testNumber retainCount]);
    NSLog(@"self.label retain count = %d",[self.label retainCount]);

    self.label.text = [NSString stringWithFormat:@"%d %d %d",_testNumber.integerValue,self.testNumber.integerValue,testNumber.integerValue ];
    NSLog(@"self before release retain count = %d",[self retainCount]);

    [self release];
    NSLog(@"self after release retain count = %d",[self retainCount]);
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)dealloc {
    NSLog(@"_label after before retain count = %d",[_label retainCount]);

    [_label release];
    NSLog(@"_label after release retain count = %d",[_label retainCount]);


    [super dealloc];
}

输出:

2013-04-08 15:31:28.503 propertiesTest[5561:907] self.testNumber retain count = 2
2013-04-08 15:31:28.507 propertiesTest[5561:907] self.label retain count = 3
2013-04-08 15:31:28.509 propertiesTest[5561:907] self before release retain count = 3
2013-04-08 15:31:28.510 propertiesTest[5561:907] self after release retain count = 2
2013-04-08 15:31:28.532 propertiesTest[5561:907] _label after before retain count = 3
2013-04-08 15:31:28.534 propertiesTest[5561:907] _label after release retain count = 2

【问题讨论】:

标签: ios objective-c


【解决方案1】:

系统的任何其他部分都可能保留了您的号码和标签。某些东西可能保留了它并将其发送到autorelease,并且自动释放池可能尚未耗尽。您通常不应该对对象的保留计数做出假设,除非它至少与您的代码负责的保留数量一样大。

特别是,一个视图保留了它的所有子视图。这至少占标签保留计数的 +1。

您的号码的保留计数为 2,因为 alloc 返回保留计数为 1 的对象,并且您(我假设)将其存储在 strongretain 属性中,这会增加其保留计数.您正在泄漏此对象,因为您负责释放它(以平衡alloc 执行的保留)并且您没有这样做。你应该这样重写它:

self.testNumber = [[[NSNumber alloc] initWithInt:101] autorelease];

或者像这样:

self.testNumber = [[NSNumber alloc] initWithInt:101];
[self.testNumber release];

或者像这样:

self.testNumber = [NSNumber numberWithInt:101];

或者,最好的,打开 ARC 并让编译器负责释放它。

请注意,您无需查看保留计数即可诊断此问题!只需运行静态分析器(从 Xcode 的产品菜单中选择分析)即可显示泄漏。或者,您可以通过学习和理解 Cocoa 内存管理约定(这就是我所做的)来诊断它。阅读Advanced Memory Management Programming Guide。它并没有那么先进。

如果您想了解您的号码或标签在哪里保留和发布,最好的方法是使用分配工具。有关详细信息,请参阅this answer。还有this answer

【讨论】:

  • 这是一个重复,但我想知道这一点:self.testNumber = [[NSNumber alloc] initWithInt:101]; 的部分怎么样在这种情况下,retainCount 显示 2 应该是正确的。但是我应该使用“弱”来代替分配吗?它正在执行双重保留。
  • 您无需担心保留计数。 “弱”是什么意思?属性的 weak 属性仅在启用 ARC 并且您已禁用 ARC 时才有效。如果您想保证 NSNumber 实例保持不变,您需要保留它(通过将其分配给 strongretain 属性来实现)。
【解决方案2】:

从 obj-c 编码的角度来看,我不会纠结于保留计数。我会考虑使用 ARC(强烈推荐恕我直言,将帮助您编写可维护、清晰的代码并消除常见的内存管理错误)。

根据您的具体问题,_label 被多个对象保留。

  1. 您的控制器将其保留在 _label ivar 中。
  2. 它的superview 保留它
  3. 根据您的代码,它可以保留在其他地方

编辑 - 如果您对 ARC 持怀疑态度,请阅读本文

诚然,我是 ARC 皈依者。我确实了解手动引用计数(旧方法)。一旦我切换到 ARC,我就没有回头。我不打算在这里写长篇大论,但如果你是怀疑论者,这个链接值得一看。最后,如果您还没有准备好或者有自己的理由想要使用 MRC,那就去做吧。这是我的看法,希望有用。

http://www.learn-cocos2d.com/2012/06/mythbusting-8-reasons-arc/

【讨论】:

  • 哦,干净的代码和消除常见的 MM 错误与 ARC 无关,它与编程风格和理解原理有关。我看到程序员用 ARC 做可怕的事情,而且错误几乎不可见,因为没有明确的 retainrelease。更短的代码是的,但甚至没有更清晰或更明显。有时使用 ARC 会很痛苦(例如块)。
  • 每个人都有。 ARC 并不是解决糟糕编码的灵丹妙药。我不是这个意思。 ARC 消除了不必担心保留和释放语义的负担。我不同意 ARC 在使用块时很痛苦。块会自动在其中保留引用,除非您明确不希望它们这样做。
【解决方案3】:

递减retainCount 然后立即转身并释放对象有什么意义?

记住retainCount 永远不能返回零

顺便说一句:http://www.whentouseretaincount.com/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-18
    • 2015-09-27
    • 1970-01-01
    • 2012-03-05
    • 2013-12-10
    • 2011-04-19
    相关资源
    最近更新 更多