4

我被困住了!

我正在尝试创建一个自定义模式对话框。我希望它使用块作为完成处理程序来执行类似于 NSSavePanel 的操作。

我只复制了我认为需要的重要片段。

@implementation ModalWindowController
    - (void)makeKeyAndOrderFront:(id)sender
                   modalToWindow:(NSWindow*)window
                      sourceRect:(NSRect)rect
               completionHandler:(void (^)(NSInteger result))handler {

        _handler = [handler retain];

        session = [NSApp beginModalSessionForWindow:[self window]];
        [[NSApplication sharedApplication] runModalSession:session];

        [[self window] makeKeyAndOrderFrontCentered:self expandingFromFrame:rect];
    }
    - (IBAction)okButtonPressed:(id)sender {
        [[self window] orderOut:self];
        _handler(NSOKButton);
        [NSApp endModalSession:session];
    }

@end

现在我可以使用以下代码调用它:

[self.modalWindowController makeKeyAndOrderFront:self
                                   modalToWindow:[[self view] window]
                                      sourceRect:sr
                               completionHandler:^(NSInteger result) {
    NSLog(@"Inside Block");
    if ( result == NSOKButton ) {
        // do something interesting here
    }
}];
NSLog(@"Errg");

然而一切顺利,在方法 makeKeyAndOrderFront:modalToWindow:sourceRect:completionHandler: 完成后它不会阻塞线程,因此即使用户没有选择“ok”或“cancel”也会打印“Errg”。此时会显示模态窗口,用户单击“确定”,然后执行 _handler 块。但是,如果我试图访问块中的局部变量,并且应用程序崩溃,因为一切都已经清理完毕。

从 makeKeyAndOrderFront:... 方法阻塞主线程的最佳方法是什么?这是使用块实现完成处理程序的正确方法吗?

4

1 回答 1

5

你的线路

_handler=[handler retain];

应该

_handler=[handler copy];

那应该可以解决您的问题,即在调用完成处理程序之前局部变量已经消失。 [handler copy]处理块中引用的局部变量,因此即使在程序流程退出您创建块的方法之后,局部变量也不会消失。

请记住以下事实:

  1. 块实例捕获块内引用的局部变量。
  2. 但是,块实例在堆栈上。当程序的流程超出{...}您创建块的范围时,即使您保留它,它也会消失。
  3. 所以,如果你想在之后使用数据,你需要copy它,而不仅仅是retain它,就像你在这里所做的那样。Copy它会自动retain获取块中引用的所有局部对象变量。
  4. release一旦你完成它,你就需要它。它为块本身释放内存,并将release消息发送到引用的本地对象变量。但是,如果您使用 GC,则不必关心这一点。

要了解该块的更多细节,我发现 Mike Ash 的文章非常有帮助

于 2010-01-26T21:13:23.657 回答