具有块完成处理程序的自定义模态窗口

Bra*_*oss 4 cocoa modal-dialog objective-c objective-c-blocks

我被卡住了!

我正在尝试创建自定义模式对话框.我希望它使用块作为完成处理程序与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
Run Code Online (Sandbox Code Playgroud)

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

[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");
Run Code Online (Sandbox Code Playgroud)

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

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

Yuj*_*uji 5

你的路线

_handler=[handler retain];
Run Code Online (Sandbox Code Playgroud)

应该

_handler=[handler copy];
Run Code Online (Sandbox Code Playgroud)

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

请记住以下事实:

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

要理解块的更多细节,我发现文中的 位置由Mike灰非常有帮助.