关闭我的窗口时EXC_BAD_ACCESS,这也是我的应用程序的委托

时间:2011-12-04 08:52:31

标签: macos cocoa xcode4 exc-bad-access automatic-ref-counting

我写了一个Cocoa应用程序,当我关闭应用程序窗口时出现EXC_BAD_ACCESS错误。我读到这个错误通常意味着内存问题,但我有ARC mode,我不需要关心释放e.t.c. (xCode禁止我调用此函数并自动管理内存。)

错误指向主函数中的行return NSApplicationMain(argc, (const char **)argv);

这是我的应用程序代码:

.h文件:

@interface MainDreamer : NSWindow <NSWindowDelegate> 
{    
    NSTextField *dreamField;
    NSTableView *dreamTable;    
    NSImageView *dreamview;

    NSMutableArray *dreamlist;  
    NSMutableArray *dataset;
}

@property (nonatomic, retain) IBOutlet NSTextField *dreamField;
@property (nonatomic, retain) IBOutlet NSTableView *dreamTable;
@property (nonatomic, retain) IBOutlet NSImageView *dreamview;
@property (nonatomic, retain) IBOutlet NSMutableArray *dreamlist;
@property (nonatomic, retain) IBOutlet NSMutableArray *dataset;
@property (assign) IBOutlet NSWindow *window;

@end

.m文件:

@implementation MainDreamer

@synthesize window;
@synthesize dataset;
@synthesize dreamField;
@synthesize dreamlist;
@synthesize dreamview;
@synthesize dreamTable;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
    NSString *applicationPath = [[NSBundle mainBundle] bundlePath];
    NSString *filename = [applicationPath stringByAppendingPathComponent:@"dreams"];
    NSLog(self.description);

    dreamlist = [[NSMutableArray alloc] init];  
    dataset = [[NSMutableArray alloc] init];
    dataset = [NSKeyedUnarchiver unarchiveObjectWithFile:filename];
    if([dataset count] != 0) {
        int i = 0;
        while (i < [dataset count]) { 
            Dream *dr = [[Dream alloc] init];
            dr = [dataset objectAtIndex:i];
            [dreamlist addObject: dr.dreamname];         
            i++;
        }
    }    
    [dreamTable reloadData]; 
}

-(void)applicationWillTerminate:(NSNotification *)notification{       
    NSString *applicationPath = [[NSBundle mainBundle] bundlePath];
    NSString *filename = [applicationPath stringByAppendingPathComponent:@"dreams"];
    [NSKeyedArchiver archiveRootObject:dataset toFile:filename];
    NSLog(@"finish");
}

- (void) mouseUp:(NSEvent *)theEvent{
    long index = [dreamTable selectedRow];
    Dream *dr = [[Dream alloc] init];
    dr = [dataset objectAtIndex:index];
    dr.dreampicture = dreamview.image;
    [dataset replaceObjectAtIndex:index withObject:dr];
    NSLog(self.description);
}

- (void) tableViewSelectionDidChange: (NSNotification *) notification{
    long row = [dreamTable selectedRow];
    Dream *dr = [[Dream alloc] init];
    dr = [dataset objectAtIndex: row];
    if(dr.dreampicture != NULL) 
        dreamview.image = dr.dreampicture;
    NSLog(@"selected row changed");
}

班级“梦想”:

@interface Dream : NSObject <NSCoding>
{
    NSString *dreamname;
    NSImage *dreampicture;
}

@property (retain) NSString* dreamname;
@property (retain) NSImage* dreampicture;

-(id)initWithCoder:(NSCoder *)aDecoder;
-(void)encodeWithCoder:(NSCoder *)aCoder;

@end

有什么问题,为什么会发生EXC_BAD_ACCESS?我提醒我有自动引用计数(ARC)的xCode 4

由于

更新

我使用Profile查找僵尸事件。所以我发现了这个:一个Objective-C消息被发送到一个解除分配的对象(僵尸(在地址0x108d85230)

负责的来电者 - [NSApplication(NSWindowCache) _checkForTerminateAfterLastWindowClosed: saveWindows:]

我在代码中有这个功能:

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender{
    return TRUE;
}

然而,在我把它放在评论中后,这个僵尸事件继续发生。

3 个答案:

答案 0 :(得分:3)

这是错误的:

dataset = [[NSMutableArray alloc] init]; // WRONG
dataset = [NSKeyedUnarchiver unarchiveObjectWithFile:filename];

为什么呢?首先分配一个空数组,并将其存储在实例变量dataset中。但是在下一行中,用任何+unarchiveObjectWithFile:返回替换空数组。为什么这是个问题?好吧,如果您阅读了文档,如果找不到该文件,您将看到它返回nil。这意味着您现在用nil替换空数组,并且将忽略发送到dataset的所有消息(在Objective-C中默默忽略nil消息)

我假设您实际上想要从文件加载数据集,并且只有在失败的情况下才开始使用空数据集:

dataset = [NSKeyedUnarchiver unarchiveObjectWithFile:filename];
if (dataset==nil) dataset = [[NSMutableArray alloc] init];

您稍后会遇到类似的错误:

Dream *dr = [[Dream alloc] init]; // WRONG
dr = [dataset objectAtIndex:index];

您创建一个Dream对象,然后立即用数据集中的内容替换它。你真正想做的是:

Dream *dr;
dr = [dataset objectAtIndex:index];

或更短:

Dream *dr = [dataset objectAtIndex:index];

然后,您可以使用快速枚举样式for循环替换while循环:

    for (Dream *dr in dataset) {
        [dreamlist addObject: dr.dreamname];         
    }

最后,为了达到某一点,我认为EXC_BAD_ACCESS实际上并不出现在main.h中。我假设您使用Xcode 4.请在调试时使用右侧边栏中的线程/堆栈导航器来查找发生错误的实际位置。

错误实际上可能发生在applicationWillTerminate:,因为您尝试归档dataset,可能是nil,并且可能不允许归档nil

答案 1 :(得分:3)

崩溃是由于您将窗口设置为应用程序的委托。当你关闭窗口时,这是杀死它的最后一个版本,如果它是你最后一个窗口,它会导致应用程序询问它的代表是否应该退出。由于你刚刚杀死的窗口是应用程序的委托,你就会崩溃。

Longer explanation and suggestion of solution in my answer on your subsequent question.

答案 2 :(得分:1)

使用ARC,您应该使用strongweak代替retainassign