我写了一个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;
}
然而,在我把它放在评论中后,这个僵尸事件继续发生。
答案 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,您应该使用strong
和weak
代替retain
和assign
。