Пользовательское модальное окно с обработчиком завершения блока - PullRequest
4 голосов
/ 26 января 2010

Я застрял!

Я пытаюсь создать пользовательский модальный диалог. Я хотел бы, чтобы он работал аналогично 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: завершениюHandler: завершил, он не блокирует поток, поэтому «Errg» будет напечатан, даже если пользователь не выбрал «ok» или «отменить». В этом месте отображается модальное окно, где пользователь нажимает кнопку ОК, и затем выполняется блок _handler. Однако, если я пытаюсь получить доступ к локальным переменным в блоке, и приложение вылетает, поскольку все уже очищено.

Каков наилучший подход к блокировке основного потока из метода makeKeyAndOrderFront: ...? Это правильный подход к реализации обработчика завершения с использованием блоков?

1 Ответ

5 голосов
/ 27 января 2010

Ваша линия

_handler=[handler retain];

должно быть

_handler=[handler copy];

Это должно решить вашу проблему: локальные переменные исчезли до вызова обработчика завершения. [handler copy] заботится о локальных переменных, указанных в блоке, так что локальные переменные не исчезают даже после того, как поток программы вышел из метода, в котором вы сделали блок.

Запомните следующие факты:

  1. Экземпляр блока захватывает локальные переменные, указанные внутри блока.
  2. Однако экземпляр блока находится в стеке. Он исчезнет, ​​даже если вы сохраните его, когда поток программы выйдет из области действия {...}, в которой вы создаете блок.
  3. Итак, вам нужно copy, а не просто retain, если вы хотите использовать данные впоследствии, как вы это делаете здесь. Copy автоматически, retain все локальные переменные объекта, указанные в блоке.
  4. Вам нужно release, как только вы закончите с этим. Он освобождает память для самого блока и отправляет сообщение release локальным переменным объекта, на которые ссылаются. Если вы используете GC, вам не нужно об этом заботиться.

Чтобы понять больше деталей блока, я нашел статью здесь Майка Эша очень полезной.

...