EXC_BAD_ACCESS调用块 [英] EXC_BAD_ACCESS invoking a block

查看:203
本文介绍了EXC_BAD_ACCESS调用块的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

UPDATE |我已使用面板上传示例项目,并在此处崩溃: http:// w3style。 co.uk/~d11wtq/BlocksCrash.tar.gz (我知道选择...按钮什么都不做,我还没有实现它)。

UPDATE | I've uploaded a sample project using the panel and crashing here: http://w3style.co.uk/~d11wtq/BlocksCrash.tar.gz (I know the "Choose..." button does nothing, I've not implemented it yet).

UPDATE 2 |刚刚发现,我甚至不需要调用任何 newFilePanel 为了导致崩溃,我只需要在语句中使用它。

UPDATE 2 | Just discovered I don't even have to invoke anything on newFilePanel in order to cause a crash, I merely need to use it in a statement.

这也会导致崩溃:

[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
    newFilePanel; // Do nothing, just use the variable in an expression
}];

显示最后被转储到控制台的东西有时是:无法反汇编dyld_stub_objc_msgSend_stret。有时这样:不能访问内存地址0xa。

It appears the last thing dumped to the console is sometimes this: "Unable to disassemble dyld_stub_objc_msgSend_stret.", and sometimes this: "Cannot access memory at address 0xa".

我创建了自己的工作表(一个NSPanel子类),试图提供一个类似于NSOpenPanel / NSSavePanel,因为它将自身作为一张表,并在完成后调用一个块。

I've created my own sheet (an NSPanel subclass), that tries to provide an API similar to NSOpenPanel/NSSavePanel, in that it presents itself as a sheet and invokes a block when done.

这是界面:

//
//  EDNewFilePanel.h
//  MojiBaker
//
//  Created by Chris Corbyn on 29/12/10.
//  Copyright 2010 Chris Corbyn. All rights reserved.
//

#import <Cocoa/Cocoa.h>

@class EDNewFilePanel;

@interface EDNewFilePanel : NSPanel <NSTextFieldDelegate> {
    BOOL allowsRelativePaths;

    NSTextField *filenameInput;

    NSButton *relativePathSwitch;

    NSTextField *localPathLabel;
    NSTextField *localPathInput;
    NSButton *chooseButton;

    NSButton *createButton;
    NSButton *cancelButton;
}

@property (nonatomic) BOOL allowsRelativePaths;

+(EDNewFilePanel *)newFilePanel;

-(void)beginSheetModalForWindow:(NSWindow *)aWindow completionHandler:(void (^)(NSInteger result))handler;
-(void)setFileName:(NSString *)fileName;
-(NSString *)fileName;
-(void)setLocalPath:(NSString *)localPath;
-(NSString *)localPath;
-(BOOL)isRelative;

@end

实现中的关键方法:

-(void)beginSheetModalForWindow:(NSWindow *)aWindow completionHandler:(void (^)(NSInteger result))handler {
    [NSApp beginSheet:self
       modalForWindow:aWindow
        modalDelegate:self
       didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
          contextInfo:(void *)[handler retain]];
}

-(void)dismissSheet:(id)sender {
    [NSApp endSheet:self returnCode:([sender tag] == 1) ? NSOKButton : NSCancelButton];
}

-(void)sheetDidEnd:(NSWindow *)aSheet returnCode:(NSInteger)result contextInfo:(void *)contextInfo {
    ((void (^)(NSUInteger result))contextInfo)(result);
    [self orderOut:self];
    [(void (^)(NSUInteger result))contextInfo release];
}

这一切工作都提供了我的块只是一个空操作。

This all works provided my block is just a no-op with an empty body. My block in invoked when the sheet is dismissed.

EDNewFilePanel *newFilePanel = [EDNewFilePanel newFilePanel];
[newFilePanel setAllowsRelativePaths:[self hasSelectedItems]];
[newFilePanel setLocalPath:@"~/"];
[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
    NSLog(@"I got invoked!");
}];

但是一旦我尝试从块中访问面板,我就崩溃了EXC_BAD_ACCESS。例如,此崩溃:

But as soon as I try to access the panel from inside the block, I crash with EXC_BAD_ACCESS. For example, this crashes:

EDNewFilePanel *newFilePanel = [EDNewFilePanel newFilePanel];
[newFilePanel setAllowsRelativePaths:[self hasSelectedItems]];
[newFilePanel setLocalPath:@"~/"];
[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
    NSLog(@"I got invoked and the panel is %@!", newFilePanel);
}];



从调试器不能清楚的原因是。第一个项目(零0)在堆栈只是说??

It's not clear from the debugger with the cause is. The first item (zero 0) on the stack just says "??" and there's nothing listed.

堆栈中的下一项(1和2)是对 -endSheet:returnCode: -dismissSheet:。查看调试器中的变量,没有什么看起来错误/超出范围。

The next items (1 and 2) in the stack are the calls to -endSheet:returnCode: and -dismissSheet: respectively. Looking through the variables in the debugger, nothing seems amiss/out of scope.

我曾经认为面板已经发布了(因为它是自动释放的) -retain 在创建之后它不会帮助。

I had thought that maybe the panel had been released (since it's autoreleased), yet even calling -retain on it right after creating it doesn't help.

我实现这个错误吗?

推荐答案

有一个奇怪的方法是 retain code> release 它在另一个对象不是一个实例变量。

It's a little odd for you to retain a parameter in one method and release it in another, when that object is not an instance variable.

我会建议使 completionHandler 位的 beginSheet 填充一个实例变量。

I would recommend making the completionHandler bit of your beginSheet stuff an instance variable. It's not like you'd be able to display the sheet more than once at a time anyway, and it would be cleaner this way.

此外,您的<$ c $

Also, your EXC_BAD_ACCESS is most likely coming from the [handler retain] call in your beginSheet: method. You're probably invoking this method with something like (for brevity):

[myObject doThingWithCompletionHandler:^{ NSLog(@"done!"); }];

如果是这种情况,您必须 copy 该块而不是保留它。如上所述的块,生活在堆栈上。然而,如果该栈帧从执行栈弹出,则该块消失。 poof 稍后尝试访问该块将导致崩溃,因为您尝试执行不再存在并被垃圾替代的代码。因此,您必须调用块上的 copy ,将其移动到堆,它可以在它创建的堆栈帧的生命周期之外。

If that's the case, you must -copy the block instead of retaining it. The block, as typed above, lives on the stack. However, if that stack frame is popped off the execution stack, then that block is gone. poof Any attempt to access the block later will result in a crash, because you're trying to execute code that no longer exists and has been replaced by garbage. As such, you must invoke copy on the block to move it to the heap, where it can live beyond the lifetime of the stack frame in which it was created.

这篇关于EXC_BAD_ACCESS调用块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆