【问题标题】:Getting EXC_BAD_ACCESS, can't figure out how to fix it获取 EXC_BAD_ACCESS,无法弄清楚如何修复它
【发布时间】:2011-09-06 01:26:22
【问题描述】:

目前我正在学习使用 Cocoa 进行 Mac 开发的 Obj-C。我用检查器制作了一个简单的文件浏览器,以查看文件的图标和一些信息。到目前为止,一切都很好。现在我让它基于文档,所以我可以打开多个窗口。

为了告诉检查员应该检查哪个文件,我使用NSWindowDidBecomeMainNotification。在窗口之间切换效果很好,但是当我关闭所有窗口然后打开一个新窗口时它会给出EXC_BAD_ACCESS

这是处理通知的方法:

- (void)windowChanged: (NSNotification *)notification
{
    NSWindow *window = [notification object];
    BrowserWindow *doc = [[window windowController] document];

    if (currentDocument != doc) {

        [currentDocument.arrayController removeObserver: self
                                             forKeyPath: @"selectionIndex"];

        [icon setImage:nil];
        [size setStringValue:@"-"];
        [owner setStringValue:@"-"];
        [filename setStringValue:@"(none selected)"];

        [doc.arrayController addObserver: self
                              forKeyPath: @"selectionIndex"
                                 options: NSKeyValueObservingOptionNew 
                                 context: NULL];
        currentDocument = doc;
    }
}

错误发生在它在currentDocument.arrayController 上调用removeObserver:forkeyPath:。这有点道理,它试图移除不再存在的东西的观察者,因为窗口是关闭的。但是如何解决呢?我就是想不出别的了。。

有人能给我指出正确的方向吗?

感谢您的帮助! :)

--

它变得越来越奇怪了。刚刚检查了可从我所拥有的书的网站下载的示例,他们使用相同的方法,但一切正常。找不到任何差异,这让我发疯。

--

解决了!稍后再详细说明。

【问题讨论】:

  • 这是哪个类的方法?
  • retaincurrentDocument 在哪里? (我猜不是。)
  • @Rudy Velthuis 这是InspectorController的方法。
  • @Daniel R Hicks:我没有retain 它。我刚刚在removeObserver之前放置了一个NSLog和一个retainCount,就在它出错之前,它显示了这个:2011-09-05 00:43:06.015 FileBrowser1[17664:707] Cannot remove an observer <InspectorController 0x10014b730> for the key path "selectionIndex" from <NSView 0x10049a1e0> because it is not registered as an observer.
  • 上面的消息包含 NSLog,它是空的。不是 0 什么的,什么都没有。在它只显示数值之前。

标签: objective-c cocoa


【解决方案1】:

Daniel 可能是对的:您可能不保留 currentDocument。将 currentDocument 设为属性:

@property (retain) BrowserWindow *currentDocument;

并在实现部分合成:

@synthesize currentDocument;

并将您的代码更改为:

- (void) windowChanged: (NSNotification *) notification
{
    NSWindow *window = [notification object];
    BrowserWindow *doc = [[window windowController] document];

    if (self.currentDocument != doc) 
    {
        [self.currentDocument.arrayController removeObserver: self
                                                  forKeyPath: @"selectionIndex"];

        [icon setImage: nil];
        [size setStringValue: @"-"];
        [owner setStringValue: @"-"];
        [filename setStringValue: @"(none selected)"];

        [doc.arrayController addObserver: self
                              forKeyPath: @"selectionIndex"
                                 options: NSKeyValueObservingOptionNew 
                                 context: NULL];
        self.currentDocument = doc;
    }
}

您可能希望对 iconsizeownerfilename 执行相同操作。

并注意消息的警告:您可能一开始就没有将自己注册为观察者。

【讨论】:

  • 看起来有些变化,但还没有工作。有时我得到EXC_BAD_ACCESS,其他时候窗口只是打开并挂起,标题栏就像它处于非活动状态一样。仍然说:2011-09-05 00:52:35.074 FileBrowser1[17849:707] Cannot remove an observer <InspectorController 0x10043ee30> for the key path "selectionIndex" from <NSWindow 0x100165080> because it is not registered as an observer.。这对我来说实际上很有意义..关闭窗口时,这不会自动摆脱观察者吗? Iconsizeownerfilename 是 IBOutlets,他们也需要吗?
  • @GuidoH:不,当某个对象仍在观察它时被释放的对象会给你一个不同的警告,基本上就是我刚才所说的。有东西试图移除观察者,可能是你,但你还没有添加它。
  • arrayController 当然不是一个窗口,它只是一个NSArrayController。 InspectorController 作为观察者添加的唯一地方是在我的帖子中的代码中。所以第一次注册是在第一个窗口打开的时候。
  • 如果是IBOutlets,不需要保留。但是该消息似乎说您正在尝试从 NSWindow 中删除 InspectroController 作为观察者。 arrayController 是一个窗口吗?你第一次在哪里注册 InspectorController 作为观察者?
  • @GuidoH:但是消息说您正在尝试从 NSWindow 中删除观察者,而不是从 NSArrayController 中删除。这很可疑。
【解决方案2】:

为了告诉检查员应该检查哪个文件,我使用NSWindowDidBecomeMainNotification。在窗口之间切换效果很好,但是当我关闭所有窗口然后打开一个新窗口时,它会给出EXC_BAD_ACCESS

这是问题的一部分。当最后一个窗口关闭时,不会有任何窗口成为主窗口。因此,您还需要处理一个窗口 resigns 主窗口的情况,就像它关闭时(以及另一个窗口变为主窗口时)一样。

您的检查员可能应该保留文档并在延迟后切换文档,使用计时器(每次收到另一个确实成为/辞职的主要通知时,您都会推迟其触发日期)或延迟执行(您取消并重新执行)每次)。当计时器/执行触发时,找出哪个文档(如果有)是活动文档,并相应地更新检查器。

还要注意,即使有文档打开,您也可以没有活动文档(没有文档窗口是主窗口)。 About 面板和您的 Preferences 面板是实现(和测试)此功能的两种好方法。

【讨论】:

  • 在没有打开其他窗口的情况下打开一个新窗口有什么区别,在这种情况下没有currentWindow,当您关闭活动窗口并且另一个变为活动窗口时有什么区别。在最后一种情况下,当另一个成为主窗口时,也没有主窗口?
  • @GuidoH:是的。变为活动的窗口是成为主窗口的窗口——这就是 Cocoa 中“主窗口”的含义。
  • 我的评论有点奇怪,但是我关闭的旧窗口 - 当另一个成为“主窗口”时,一个不存在?
  • @GuidoH:当您关闭作为主窗口的窗口时,它会退出主窗口。如果有任何其他窗口,其中一个将成为主窗口(您将看到其框架的外观发生变化以反映这一点)。如果您关闭的窗口是您的最后一个窗口(即您没有其他打开的窗口),则没有窗口成为主窗口。这就是为什么您需要同时处理 resign-main-window 和 become-main-window。
  • 谢谢你,彼得。会研究一下并考虑如何实施您的解决方案。对于我,这说得通。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-18
  • 1970-01-01
相关资源
最近更新 更多