UPDATE | Ich habe ein Beispielprojekt mit dem Panel hochgeladen und stürzte hier: http://w3style.co.uk/~d11wtq/BlocksCrash.tar.gz (Ich weiß, dass die Schaltfläche "Wählen ..." nichts tut, ich habe es noch nicht implementiert).EXC_BAD_ACCESS Aufruf eines Blocks
UPDATE 2 | Gerade entdeckt, ich muss nicht einmal auf newFilePanel
irgendetwas aufrufen, um einen Absturz zu verursachen, ich muss es nur in einer Aussage verwenden.
Dies führt auch zu einem Absturz:
[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
newFilePanel; // Do nothing, just use the variable in an expression
}];
es das letzte, was auf der Konsole abgeladen erscheint, ist manchmal: „Unfähig dyld_stub_objc_msgSend_stret zu zerlegen“, und manchmal: „Can not Speicher zugreifen Adresse 0xa“ .
Ich habe mein eigenes Blatt (eine NSPanel-Unterklasse) erstellt, das versucht, eine API ähnlich wie NSOpenPanel/NSSavePanel bereitzustellen, indem es sich als ein Blatt darstellt und einen Block aufruft, wenn das erledigt ist.
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 in 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 alles funktioniert bereitgestellt mein Block ist nur 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 Block der Platte zuzugreifen, von innen, ich mit EXC_BAD_ACCESS abstürzen. Zum Beispiel stürzt dies ab:
Es ist nicht klar aus dem Debugger mit der Ursache ist. Das erste Element (Null 0) auf dem Stapel sagt nur "??" und da ist nichts aufgeführt. Die nächsten Elemente (1 und 2) im Stapel sind die Aufrufe an -endSheet:returnCode:
bzw. -dismissSheet:
. Beim Durchsehen der Variablen im Debugger scheint nichts/nicht im Bereich zu sein.
Ich hatte gedacht, dass das Panel vielleicht veröffentlicht worden war (da es automatisch freigegeben wurde), aber sogar -retain
direkt nach dem Erstellen anzurufen, hilft nicht.
Implementiere ich das falsch?
Brilliant, danke! Das Kopieren löst alles. Danke auch für die Eingabe, wo ich beharre/freigebe. Es fühlte sich selbst für mich merkwürdig an, aber ich folgte irgendwo in der Apple-Dokumentation einem Muster, wenn ich mich richtig erinnere (sie behielten und veröffentlichten eine NSNummer). Ein flüchtiger ivar ist wahrscheinlich weniger riskant. – d11wtq
Vergessen zu fügen, Ihre Antwort war sehr klar, es macht Sinn, dass Sie es kopieren müssten, um es in diesem Fall herum zu halten, da das Panel asynchron aufgerufen wird und der Stapel natürlich endet. – d11wtq
Ich empfehle auch Block_copy und Block_release –