EXC_BAD_ACCESS Berufung auf einen block
UPDATE | ich habe hochgeladen ein Beispiel-Projekt mit dem panel und stürzt sich hier: http://w3style.co.uk/~d11wtq/BlocksCrash.tar.gz (ich weiß, der "..." - Schaltfläche, die nichts tut, habe ich nicht implementiert, die es noch).
UPDATE 2 | Gerade entdeckt habe ich auch nicht aufrufen, alles auf newFilePanel
um einen Absturz verursachen, ich nur brauchen, um es in einem statement.
Dies führt auch zu einem crash:
[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
newFilePanel; //Do nothing, just use the variable in an expression
}];
Scheint es, die Letzte Sache, die gedumpten auf der Konsole ist manchmal: "Nicht zerlegen dyld_stub_objc_msgSend_stret.", und manchmal ist dieser: "kein Zugriff auf Speicher bei Adresse 0xa".
Habe ich meine eigene Platte (eine NSPanel Unterklasse), das versucht, eine API bereitstellen, ähnlich NSOpenPanel/NSSavePanel, dass es präsentiert sich als ein Blatt und beruft sich dabei einen block, wenn Sie fertig.
Hier ist die Schnittstelle:
//
// 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
Und die wichtigsten Methoden innerhalb der Umsetzung:
-(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];
}
Das ganze funktioniert mein block ist einfach ein no-op mit einem leeren Körper. Mein block wird aufgerufen, wenn das Blatt geschlossen wird.
EDNewFilePanel *newFilePanel = [EDNewFilePanel newFilePanel];
[newFilePanel setAllowsRelativePaths:[self hasSelectedItems]];
[newFilePanel setLocalPath:@"~/"];
[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
NSLog(@"I got invoked!");
}];
Aber sobald ich versuche, den Zugriff auf die Systemsteuerung von innen aus dem block, ich crash EXC_BAD_ACCESS. Zum Beispiel, dieses stürzt ab:
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);
}];
Es ist nicht klar, aus dem debugger mit, die Ursache ist. Das erste Element (0) auf den stack sagt nur "??" und es ist nichts aufgeführt.
Den nächsten Artikel (1 und 2) in dem Stapel sind die Aufrufe -endSheet:returnCode:
und -dismissSheet:
beziehungsweise. Der Blick durch die Variablen im debugger, nichts scheint falsch/out of scope.
Hatte ich gedacht, dass vielleicht das panel veröffentlicht wurde (da es autoreleased), aber auch fordern -retain
auf it-Recht nach der Erstellung nicht helfen.
Bin ich in der Umsetzung das falsch?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es ist ein wenig seltsam für Sie, um
retain
einen parameter in einer Methode undrelease
es in einem anderen, wenn das Objekt nicht eine Instanz-variable.Ich würde empfehlen, den
completionHandler
bisschenbeginSheet
Zeug eine Instanz-variable. Es ist nicht so, Sie würde in der Lage sein, um anzuzeigen, das Blatt mehr als einmal in einer Zeit sowieso, und es wäre sauberer dieser Weg.Auch, Ihre
EXC_BAD_ACCESS
ist wahrscheinlich kommen aus der[handler retain]
nennen Sie in IhrerbeginSheet:
Methode. Du bist wahrscheinlich der Aufruf dieser Methode mit etwas wie (aus Platzgründen):Wenn das der Fall ist, Sie muss
-copy
den block, anstatt das behalten Sie. Der block, wie oben eingegeben, lebt auf dem stack. Allerdings, wenn das stack-frame tauchte aus dem ausführungsstapel, dann ist der block Weg ist. Puh Jeder Versuch, Zugriff auf den block wird es später zu einem Absturz führen, weil man versucht code auszuführen, der nicht mehr vorhanden und wurde ersetzt durch Müll. Als solche müssen Sie aufrufencopy
auf den block zu verschieben, um den heap, wo Sie Leben können, über die gesamte Lebensdauer des stack-Rahmens an, in dem es erstellt wurde.Versuchen, die Definition Ihrer EDNewFilePanel mit der
__block
modifier:Diese sollten weiterhin das Objekt, wenn der block aufgerufen wird, die möglicherweise nach dem Panel-Objekt freigegeben wird. Als ein unbedeutender Nebeneffekt, dadurch wird es auch Mutationen innerhalb des Blocks scope.
__block
. Trotzdem danke (PS: ich habe noch einen link zu einem Beispiel-Projekt in Frage).