NSSavePanel nil внутри блока обработчика завершения

Я пытаюсь сохранить содержимое представления в файл PDF. Код, который вы видите, находится внутри класса, который наследуется от NSView:

- (IBAction) savePDF: (id) sender
{
    __block NSSavePanel* panel=[NSSavePanel savePanel];
    [panel setAllowedFileTypes: [NSArray arrayWithObject: @"pdf"]];
    [panel beginSheetModalForWindow: [self window] completionHandler: ^(NSInteger result)
     {
         if(result==NSOKButton)
         {
             NSCAssert(panel!=nil,@"panel is nil");
             NSData* data=[self dataWithPDFInsideRect: [self bounds]];
             NSError* error;
             BOOL successful=[data writeToURL: [panel URL] options: 0 error: &error];
             if(!successful)
             {
                 NSAlert* alert=[NSAlert alertWithError: error];
                 [alert runModal];
             }
         }
     }];
    panel=nil;
}

Метод запускается с помощью меню.
Проблема в том, что утверждение не выполняется:

NSCAssert(panel!=nil,@"panel is nil");

Даже если я объявил указатель NSSavePanel __block. Почему?

2 ответа

Решение

На самом деле, ответ состоит в том, чтобы удалить __block спецификатор.

Я запустил ваш код с / без него. Assert терпит неудачу с этим, работая без него (__blockспецификатор, то есть).

Теперь, чтобы ответить на почему:

Я полагаю __block Спецификатор был сделан для глобальных переменных / переменных экземпляра, а не локальных переменных, хотя я могу ошибаться.


X'D... Я не знаю, что поразило меня, но проверьте это:

NSSavePanel* panel=[NSSavePanel savePanel];

[panel setAllowedFileTypes: [NSArray arrayWithObject: @"pdf"]];
[panel beginSheetModalForWindow: [self window] completionHandler: ^(NSInteger result)
 {
     if(result==NSOKButton)
     {
         dispatch_async(dispatch_get_main_queue(), ^{
             NSCAssert(panel!=nil,@"panel is nil");
             NSData* data=[self dataWithPDFInsideRect:[self bounds]];
             NSError* error;
             BOOL successful=[data writeToURL: [panel URL] options: 0 error: &error];
             if(!successful)
             {
                 NSAlert* alert=[NSAlert alertWithError: error];
                 [alert runModal];
             }
         });
     }
 }];
panel=nil;

Я только что решил, позвольте мне обернуть его в блок GCD и нарисовать в главном потоке. Ваш код работает великолепно. Представление рисуется в PDF, как и ожидалось, и я могу подтвердить, что:D.

Что касается вопроса, это кажется вполне очевидным. Вызов границ в фоновом потоке и рисование - нет-нет.

Это было весело, спасибо: D

Решения: по неизвестной причине, которая для меня до сих пор остается загадкой, если я сделаю IBAction для класса представления, [self bounds] всегда повторяет NSZeroRect. Внутри других методов он возвращает правильные значения. Так что я решил эту проблему, удалив спецификатор __block из NSSavePanel и перезапись (также повторная привязка) метода в классе делегата приложения.

Другие вопросы по тегам