代码之家  ›  专栏  ›  技术社区  ›  BJ Homer

在标准实践中,谁拥有NSWindowController?

  •  12
  • BJ Homer  · 技术社区  · 15 年前

    我正在寻求进一步澄清后,看到了 What is responsible for releasing NSWindowController objects?

    - (IBAction)addNewItem:(id)sender {
      LibraryItemEditorController *editorController = 
        [[LibraryItemEditorController alloc] 
              initWithWindowNibName:@"LibraryItemEditor"];
    
      [editorController showWindow:nil];
      // editorController is "leaked" here, it seems.
    }
    

    我不能释放(也不能自动释放) editorController 在…的结尾 addNewItem: ; 如果我松开它,窗口立即消失。但是,我确实希望窗口控制器在其窗口关闭后释放。在苹果的 Window Programming Guide ,我读到以下内容:

    如果你想关闭一个窗口 创建窗口和窗口控制器 当它不是一个国家的一部分时就走开 文档,您的 NSWindowController 能观察到 NSWindowWillCloseNotification 或者 窗口委托,实现 windowWillClose: 方法和包括 您的应用程序中的以下代码行 实施:

    [self autorelease];
    

    [self autorelease] 窗口将关闭: addNewItem: windowDidClose: ,但感觉不对。此外,窗口控制器现在正在释放自己,而从未保留过自己。这一切都违背了我学到的内存管理规则。

    我的另一个选择是在父控制器上放置ivar(或 NSMutableSet 属于 窗口控制器 s) 然后再观察一下 NSWindowWillCloseNotification 在父控制器中,释放它作为响应。这更干净,可能就是我要做的。这也是一个相当多的工作,虽然,这导致我的问题。

    NSWindowDidCloseNotification 这样做的标准方式是什么?管理的标准方式是什么 NSWindowControllers 这是传统上推荐的选择,直到现在我们有了静态分析,这才是一个问题?

    2 回复  |  直到 8 年前
        1
  •  5
  •   Darren    15 年前

    听起来您的窗口是模态的,在这种情况下:

    [NSApp runModalForWindow:[editorController window]];
    [editorController release];
    

    以下是非模态窗口的一种模式:

    @implementation QLPrefWindowController
    
    + (id) sharedInstance
    {
        if (!_sharedInstance)
        {
            _sharedInstance = [[QLPrefWindowController alloc] init];
        }
        return _sharedInstance;
    }
    
    - (void)windowWillClose:(NSNotification *)notification
    {
        if ([notification object] == [self window] && self == _sharedInstance)
        {
            _sharedInstance = nil;
            [self release];
        }
    }
    

    然后,任何想要访问或显示窗口的人都可以通过 +sharedInstance 类方法。如果窗口不可见,则创建该窗口,否则将获取当前可见的窗口。

        2
  •  0
  •   Bryan    13 年前

    上面发布的非模态情况的解决方案是不正确的,因为类方法无法访问IVAR。我通过创建一个类方法(在名为LPWindowController的NSWindowController子类中)解决了这个问题,该类方法如下所示:

    + (id) autoreleasingInstanceShowingWindow
    {
        LPWindowController *obj = [[LPWindowController alloc] initWithWindowNibName:@"myWindow"];
        [obj showWindow:[NSApp delegate]];
    
        return obj; 
    }
    

    上述方法返回保留计数为1的LPWindowController实例。它还显示控制器的窗口。这一点很重要,因为否则我们将不得不依靠调用方调用“showWindow:”来显示LPWindowController的窗口。如果调用方未能做到这一点(这可能是一个bug),控制器将永远不会被释放。通过在alloc/init控制器时强制显示窗口,我们避免了这个陷阱。

    接下来,在IB中,我们将窗口的委托设置为LPWindowController类,并将其添加到该类中:

    - (void) windowWillClose:(NSNotification *)notification
    {
        [self autorelease];
    }
    

    LPWindowController *cont = [LPWindowController autoreleasingInstanceShowingWindow];
    cont = nil;
    

    第二行很重要。首先,它消除了关于“未使用的变量cont”的警告。其次,它消除了指针悬空的危险。一旦LPWindowController实例释放自身,如果cont未被nilled out,它将指向垃圾内存。

    无论如何,这是我建议的解决这个问题的方法。