没有ARC,应用程序没有释放由手创建的对象而崩溃

时间:2013-08-01 12:27:52

标签: cocoa automatic-ref-counting nsalert accessoryview

目前我没有在我的应用程序中使用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发布],为什么不崩溃?它甚至没有泄漏。

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

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

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

感谢您的关注!

2 个答案:

答案 0 :(得分:3)

  1. 确实泄漏了。在dealloc上放置一个断点(或者创建一个NSAlert的子类并向dealloc添加一个日志语句)来显示这个
  2. 应该发布访问者视图。您alloc它然后它将被alertView
  3. 保留
  4. 以下是when to use retainCount
  5. 的简明指南

答案 1 :(得分:2)

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

内存管理的第一条规则:

  1. Use ARC.
  2. 如果您不能遵循规则一(例如,您正在为OS X 10.5开发),那么这是规则:

    1. 您必须通过调用+alloc…+new…来平衡对-…copy…-retain-release-autorelease的每次通话。
    2. 真的是这样。 Everything else只是评论,可以帮助您遵循该规则。因此,您致电[NSAlert alloc][NSTextField alloc],您需要在这些对象上调用release

        

      为什么不崩溃?

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

        

      为什么不泄漏?

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

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

        

      附件视图不应该被释放。

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

        

      ... retainCount ...

      永远不要使用-retainCount。甚至不用于调试。甚至没有其他任何东西。没有必要retainCount会给你一些信息,而这些信息会比混淆更具启发性。为什么它比你想象的要大?因为其他对象保留了警报视图?哪个对象?那不是你的事。这是一个内部实施细节,可能会有变化。它可能是待处理的autorelease次呼叫,暂时显示为“过高retainCount”。它可能是运行循环。它可能是一个内部控制器。它可能是任何东西。调用retainCount会告诉您没有用处。

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