EXC_BAD_ACCESS invocando un bloque
ACTUALIZAR | He subido un proyecto de muestra usando el panel y fallando aquí:http://w3style.co.uk/~d11wtq/BlocksCrash.tar.gz (Sé que el botón "Elegir ..." no hace nada, aún no lo he implementado).
ACTUALIZACIÓN 2 | Acabo de descubrir que ni siquiera tengo que invocar nada ennewFilePanel
Para causar un bloqueo, simplemente necesito usarlo en una declaración.
Esto también provoca un bloqueo:
[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
newFilePanel; // Do nothing, just use the variable in an expression
}];
Parece que lo último que se arrojó a la consola es a veces esto: "No se puede desmontar dyld_stub_objc_msgSend_stret" y, a veces, esto: "No se puede acceder a la memoria en la dirección 0xa".
He creado mi propia hoja (una subclase de NSPanel), que intenta proporcionar una API similar a NSOpenPanel / NSSavePanel, ya que se presenta como una hoja e invoca un bloque cuando termina.
Aquí está la interfaz:
//
// 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
Y los métodos clave dentro de la implementación:
-(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];
}
Todo esto funciona siempre que mi bloque sea solo un no-op con un cuerpo vacío. Mi bloqueo se invoca cuando se descarta la hoja.
EDNewFilePanel *newFilePanel = [EDNewFilePanel newFilePanel];
[newFilePanel setAllowsRelativePaths:[self hasSelectedItems]];
[newFilePanel setLocalPath:@"~/"];
[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
NSLog(@"I got invoked!");
}];
Pero tan pronto como intento acceder al panel desde el interior del bloque, me cuelgo con EXC_BAD_ACCESS. Por ejemplo, esto se bloquea:
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);
}];
No está claro del depurador con la causa. El primer elemento (cero 0) en la pila solo dice "??" Y no hay nada en la lista.
Los siguientes elementos (1 y 2) en la pila son las llamadas a-endSheet:returnCode:
y-dismissSheet:
respectivamente. Mirando a través de las variables en el depurador, nada parece estar fuera de alcance.
Pensé que tal vez el panel había sido lanzado (ya que se lanzó automáticamente), pero incluso llamé-retain
en él justo después de crearlo no ayuda.
¿Estoy implementando esto mal?