合成@property(弱)IBOutlet NSWindow *窗口时的EXC_BAD_INSTRUCTION

时间:2011-10-26 16:34:06

标签: objective-c automatic-ref-counting weak-references iboutlet

我是ObjC / Cocoa和Mac开发的新手,并且玩弄了基础知识。

Lion上的Xcode 4.2中新的Cocoa应用程序的简单默认模板如下所示:

// AppDelegate.h
#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>

@property (assign) IBOutlet NSWindow *window;

@end



// Appdelegate.m
#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
}

@end

我一直在用它作为各种实验的基础。阅读自动引用计数(项目设置使用) - 例如this article - 我假设可以,甚至替换assign限定符NSWindow *windowweak,但似乎并非如此。

该应用构建正常,但在启动期间挂起,Thread 1: Program received signal: "EXC_BAD_INSTRUCTION"位于AppDelegate.m的{​​{1}}行。{/ p>

将限定符更改为@synthesize window = _window;会使该程序正常运行,但我无法看到从strong转到assign有何意义。我的印象是,非ARC / ARC的配对分配/弱,保留/强。

更有经验的编码朋友建议,即使strong限定符导致weak过早释放,并且某些访问尝试失败,例外也应为window,而不是EXC_BAD_ACCESS {1}}。

我显然在这里遗漏了一些东西,但我不知道是什么。

编辑:仔细查看崩溃时gdb输出后,同一位朋友向我指出this article by Mike Ash对此有所了解。由于我理解的原因,EXC_BAD_INSTRUCTION和其他一些覆盖NSWindowretain的类不能成为归零弱引用的目标。有趣的是,将属性声明更改为有效:

release

...即使Apple's documentation for Declared Properties中未提及@property (unsafe_unretained) IBOutlet NSWindow *window;

有了这个,已经修改过的问题:

什么是正确的方式去这里?坚持unsafe_unretained尽管在网上提到它不应该与ARC一起使用?转到assign?继续使用strong因为它似乎有用吗?还有别的吗?

3 个答案:

答案 0 :(得分:8)

从概念上讲,'弱'是OS X上顶级IBOutlet的正确限定符(iOS是另一个故事)。但是,要创建一个适当的弱引用,在重新分配时为零需要来自Objective C运行时的协作。覆盖保留或释放的类会破坏此支持,因此您无法创建对它们的弱引用。 UIWindow就是这样一个类。

这就是模板使用'assign'的原因。如果启用ARC,也许应该使用同义词'unsafe_unretained'。在任何一种情况下,你都有一个不归零的简单弱引用。

答案 1 :(得分:3)

Mike Ash的博客讨论了一些Cocoa类的问题。

在页面的中间部分查找:Friday Q&A ARC。查看/搜索以“ARC实现归零弱引用...”开头的文本

问题是某些类不处理__weak带来的归零弱引用。解决方案是使用普通ARC模板提供的 assign

嗯,回答第二个问题,即使Apple的模板在使用ARC时也使用窗口分配。所以你现在可能很安全。但是你的里程可能在将来有所不同。

答案 2 :(得分:2)

Mike Ash has a very good explanation of what's going wrong here(搜索“ARC的实施”)。它的要点是NSWindow类特别不支持弱引用:显然是因为它依赖于覆盖保留和释放以及它自己的实现。

我希望在遗留的Cocoa类中分散更多这样的问题,而这些问题似乎还没有记录 - 相反,你会发现运行时错误。 (我希望在某些时候这也会成为编译器警告。)