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 и перезапись (также повторная привязка) метода в классе делегата приложения.