代码之家  ›  专栏  ›  技术社区  ›  Brad G

带有块完成处理程序的自定义模式窗口

  •  4
  • Brad G  · 技术社区  · 14 年前

    我被卡住了!

    我正在尝试创建自定义模式对话框。我希望它使用一个块作为完成处理程序来执行与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”。此时将显示模式窗口,用户单击“确定”,然后执行处理程序块。但是,如果我试图访问块中的局部变量,应用程序会崩溃,因为一切都已经清理干净了。

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

    1 回复  |  直到 13 年前
        1
  •  5
  •   Yuji    14 年前

    你行

    _handler=[handler retain];
    

    应该是

    _handler=[handler copy];
    

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

    记住以下事实:

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

    为了了解该块的更多细节,我找到了这篇文章 here 迈克·阿什非常有帮助。