UPDATE |パネルを使用してサンプルプロジェクトをアップロードしました。ここでは、http://w3style.co.uk/~d11wtq/BlocksCrash.tar.gz(「選択...」ボタンは何もしません。まだ実装されていません)。ブロックを呼び出すEXC_BAD_ACCESS
更新日2 |ちょうど私がちょうど文句でそれを使用する必要があるクラッシュを引き起こすためにnewFilePanel
の何かを呼び出す必要はないことを発見しました。
これもクラッシュが発生します、そして時には、この「dyld_stub_objc_msgSend_stretを分解することができません。」:コンソールにダンプ最後のものは時々これです表示されます
[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
newFilePanel; // Do nothing, just use the variable in an expression
}];
「アドレスは0xaでメモリにアクセスすることはできません」 。
自分自身のシート(NSPanelサブクラス)を作成しました。NSOpenPanel/NSSavePanelに似たAPIを提供しようとしています。シートとして表示され、完了するとブロックが呼び出されます。
//
// 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];
}
このすべての作品は私のブロックが空のボディを持つだけで何もしません提供
はここインターフェースです。シートが解除されると、ブロックが呼び出されます。
EDNewFilePanel *newFilePanel = [EDNewFilePanel newFilePanel];
[newFilePanel setAllowsRelativePaths:[self hasSelectedItems]];
[newFilePanel setLocalPath:@"~/"];
[newFilePanel beginSheetModalForWindow:[windowController window] completionHandler:^(NSInteger result) {
NSLog(@"I got invoked!");
}];
しかし、ブロック内からパネルにアクセスしようとすると、EXC_BAD_ACCESSでクラッシュします。たとえば、次のようにクラッシュします。
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)は "??"リストには何もありません。
スタック内の次の項目(1と2)はそれぞれ-endSheet:returnCode:
と-dismissSheet:
の呼び出しです。デバッガの変数を調べると、範囲外のものはありません。
パネルがリリースされている(自動リリースされているので)と思っていましたが、作成した直後に-retain
と呼んでもそれは役に立ちません。
私はこれを間違って実装していますか?
華麗な、ありがとう!コピーはすべてを解決します。また、私が保持している/解放している場所に関する入力にも感謝します。それは私にとっても奇妙に感じましたが、正しく思い出したら(NSNumberを保持していてリリースしていた)リンゴの文書のどこかにパターンをたどっていました。一時的な象牙は恐らく危険性が低いです。 – d11wtq
追加するのを忘れてしまったあなたの答えは非常にはっきりしていました。パネルが非同期に呼び出され、スタックが終了するので、このケースを回避するためにコピーする必要があります。 – d11wtq
Block_copyとBlock_releaseも使用することをお勧めします –