UPDATE | I downloaded the sample project using the panel and crashed here: http://w3style.co.uk/~d11wtq/BlocksCrash.tar.gz (I know that the "Select ..." button does nothing, I have not implemented it yet )
UPDATE 2 | I just discovered that I donβt even need to call anything on newFilePanelto cause a crash, I just need to use it in the instructions.
This also causes a crash:
[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
newFilePanel;
}];
It seems that the last thing that was dumped to the console, sometimes this: "Unable to parse dyld_stub_objc_msgSend_stret.", And sometimes it: "Unable to access memory at address 0xa".
I created my own sheet (a subclass of NSPanel) that tries to provide an API similar to NSOpenPanel / NSSavePanel in that it represents itself as a sheet and calls the block when it is done.
Here's the interface:
#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
And the key methods inside the implementation:
-(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];
}
It all works when my block just doesn't work with an empty body. My block is called when the sheet is rejected.
EDNewFilePanel *newFilePanel = [EDNewFilePanel newFilePanel];
[newFilePanel setAllowsRelativePaths:[self hasSelectedItems]];
[newFilePanel setLocalPath:@"~/"];
[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
NSLog(@"I got invoked!");
}];
But as soon as I try to access the panel from inside the block, I crash with EXC_BAD_ACCESS. For example, this results in a crash:
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);
}];
This is not clear from the debugger with the reason. The first element (zero 0) on the stack just says "??" and nothing is indicated there.
The following items (1 and 2) on the stack are calls -endSheet:returnCode:and, -dismissSheet:respectively. Looking through the variables in the debugger, nothing seems wrong / inaccessible.
, , , ( ), -retain .
?