【问题标题】:No ARC, the app didn't crash without releasing the object that created by hands没有 ARC,应用程序不会在不释放手动创建的对象的情况下崩溃
【发布时间】:2013-08-01 12:27:51
【问题描述】:

目前我没有在我的应用程序中使用 ARC,我尝试创建一个 NSAlert 对象作为局部变量,在函数结束时,我没有释放它。 我预计应用程序会崩溃,功能代码在这里。

 #define GLOBAL_VARIABLE      0

 NSString *msgText = [self.defaultValueTextFiled stringValue];
    NSString *informativeText = @"Informative Text";

  #if !GLOBAL_VARIABLE
        NSAlert *alertView = nil;
  #endif

    if (alertView == nil)
    {
        alertView = [[NSAlert alloc] init];
        [alertView setMessageText:msgText];
        [alertView setInformativeText:informativeText];

        NSTextField *accessory = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,200,22)];
        [accessory setStringValue:@"accessory result"];
        [alertView setAccessoryView:accessory];
    }

    NSView *accessory= nil;
    NSInteger result = [alertView runModal];
    if (result == NSAlertAlternateReturn)
    {
        accessory = [alertView accessoryView];
        if (accessory != nil)
        {
            NSTextField *txtFiled = (NSTextField *)accessory;
            NSLog(@"%ld", [accessory retainCount]);
            NSString *str = [txtFiled stringValue];
            NSLog(@"%ld", [accessory retainCount]);
            [self.resultValueTextField setStringValue:str];
            NSLog(@"%ld", [accessory retainCount]);
        }
    }

问题: (1) 到底没有【alertView release】,为什么不崩溃?它甚至没有泄漏。

(2) 参考here,附件视图不应该被释放。但是,我尝试在 [alertView runModal] 之前释放视图,然后稍后获取它的 stringValue,这可以工作。为什么?

(3)函数retainCount的返回值很有意思。当我创建alertView对象时,alertView的retainedCount是3。(为什么?)

在[alertView setAccessoryView:accessory]之前,附件的retainedCount为1,执行后变为2。这是正常和正确的。但是,上面代码的日志结果,它们是20、21、22。它们是怎么来的?

感谢您的关注!

【问题讨论】:

    标签: cocoa automatic-ref-counting nsalert accessoryview


    【解决方案1】:
    1. 确实会泄漏。在 dealloc 上放一个断点(或者创建一个 NSAlert 的子类并在 dealloc 中添加一个日志语句)来显示这个
    2. 配件视图应该被释放。你alloc它,然后它会被 alertView 保留
    3. 这是when to use retainCount 的简明指南。

    【讨论】:

    • whentouseretaincount.com 是 Cocoa 世界最棒的服务之一,就在 whathaveyoutried.com 之后。谢谢你。
    【解决方案2】:

    内存管理的规则通常很简单。大多数问题来自过度思考它们并试图猜测系统的其他部分将要做什么,而不是仅仅遵循书面规则。

    内存管理第一条规则:

    1. Use ARC.

    如果您不能遵循规则一(例如,您正在像我一样为 OS X 10.5 进行开发),那么以下是规则:

    1. 您必须在拨打+alloc…+new…-…copy…-retain 与拨打-release-autorelease 之间取得平衡。

    原来如此。 Everything else 实际上只是帮助您遵守该规则的评论。因此,您调用了[NSAlert alloc][NSTextField alloc],您需要在这些对象上调用release

    为什么不崩溃?

    因为除非导致内存不足,否则泄漏不会崩溃。

    为什么不泄露?

    最可能的原因是您只运行了一次,然后期望 Instruments 检测到泄漏。如果您只运行一次,它可能不会显示。这取决于NSAlert 在内部是如何实现的。 Instruments 通过遍历系统中的所有指针并确定是否有任何可访问指针仍然引用一块分配的内存来发现泄漏。有很多情况是“leak is not a leak”。

    但这也表明您没有运行静态分析器,因为分析器肯定应该检测到泄漏。一直运行静态分析器 (Cmd-Shift-B) 并清理它找到的内容。

    附件视图不应被释放。

    这不是您引用的链接所说的。您不应添加额外 release。但是在引用的代码中,你会注意到他们释放视图是为了平衡自己的+alloc

    …retainCount…

    永远不要使用-retainCount。甚至不用于调试。甚至不为别的。 retainCount 不会在任何时候向您返回一条比令人困惑的信息更具启发性的信息。为什么它比你想象的要大?因为其他对象正在保留警报视图?哪些对象?那不关你的事。这是一个内部实现细节,可能会发生变化。它可能正在挂起的autorelease 调用,暂时显示为“太高retainCount”。它可能是运行循环。它可能是一个内部控制器。它可以是任何东西。致电retainCount 不会告诉您任何有用的信息。

    既然您了解了手动内存管理,请切换到 ARC 和 think about object graphs 而不是保留计数。这是处理内存的更好方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多