【问题标题】:NSSavePanel nil inside the completion handler block完成处理程序块内的 NSSavePanel nil
【发布时间】:2012-08-05 02:20:16
【问题描述】:

我正在尝试将视图的内容保存到 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。为什么?

【问题讨论】:

    标签: objective-c cocoa osx-lion nssavepanel


    【解决方案1】:

    其实答案就是去掉__block这个说明符。

    我在有/没有它的情况下运行了你的代码。断言与它一起失败,在没有它的情况下工作(即__blockspecifier)。

    现在,回答原因:

    我想__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

    【讨论】:

    • 是的,我使用 ARC。我试图删除 __block 说明符。现在断言没有失败,文件被保存。但是当我用预览打开文件时,有一个空的 PDF 文件.这是因为 [self bounds] 也没有返回正确的值,如果我尝试打印它,它会说 [self bounds].size.width 在块内为零。如何让这些变量在块内存活?
    【解决方案2】:

    解决方案:由于未知原因,这对我来说仍然是一个谜,如果我对视图类进行 IBAction,[self bounds] 总是返回 NSZeroRect。在其他方法中它返回正确的值。所以我解决了这个从 NSSavePanel 中删除 __block 说明符并重写(也重新绑定)应用委托类中的方法时出现问题。

    【讨论】:

    • 是的,我运行了您的代码,并且 bounds 也返回 CGRectZero .. 我会检查一下。我也有兴趣知道。
    猜你喜欢
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    相关资源
    最近更新 更多