要約: メソッドが NSArray または NSDictionary であるcontextInfobeginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo
のオブジェクトを提供する場合、実際にはメモリ内の任意の場所への任意のポインターになります。これに対する適切な解決策は何ですか?
以下に問題を示します。
- (IBAction)testbutton:(id)sender {
NSAlert *alert = [[NSAlert alloc] init];
[alert beginSheetModalForWindow:theWindow
modalDelegate:self
idEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
contextInfo:[NSArray arrayWithObject:@"bla bla"]];
}
- (void) alertDidEnd:(NSAlert *)alert
returnCode:(NSInteger)returnCode
contextInfo:(NSArray *)contextInfo {
NSLog(@"contextInfo: %@", contextInfo);
}
NSLog は、ポインタが空の場合のクラッシュを含め、メモリ内の任意のものを出力します。ただし、contextInfo が NSString、NSNumber、または NSTextField などのアウトレットなどの単純なものであれば、問題なく動作します。また、NSArray または NSDictionary であるインスタンス変数を指定すると、機能します。
Apples のドキュメントでは、contextInfoは (void *) として宣言されているため、何でも構いません (任意のポインターでも構いません)。しかし、私はクラスを知っているので、この例では NSArray と宣言します。ただし、問題は、contextInfo を何と宣言するかに依存しません。
ガベージ コレクションがある場合、Lion で問題が発生します。
Using NSAlert beginSheetModalForWindow with contextInfo 'noa' というメッセージでは、「ガベージ コレクションを使用している場合は、インスタンス変数に格納してください。どこでもかまわないので、実行ループの最後に解放されません。 didEndSelector が対応できるようになるまで、そのままにしておいてください。」
これは良い回避策ですが、奇妙でかなり醜いものです。もっとエレガントなソリューションはありませんか?
この動作は本当に Apple が意図したものですか? それとも明らかなバグ?NSString や NSNumber などの単純なオブジェクトは問題ありませんが、NSArray は問題ありません。それが本当にバグではない場合、contextInfo の制限を指定するべきではなく、何らかの方法で明示的に保持する必要がある場合とその方法を正確に指定するべきではありませんか? または、 contextInfoがインスタンス変数でない限り、GC はこのメソッドで何も保証しませんか?