ABTRACT:
当方法beginSheetModalForWindow:modalDelegate:didEndSelector:contextInfo
为 contextInfo 提供NSArray或NSDictionary的对象时,它实际上将成为指向内存中任何位置的任意指针。对此有什么合适的解决方案?
以下说明了问题:
- (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。如果它确实不是一个bug,那么不应该指定contextInfo的限制,并且不应该准确地指定何时以及如何以某种方式明确保留它?或者除非 contextInfo 是一个实例变量,否则GC不会保证使用此方法做任何事情?