Question

I'm trying to save the content of a view into a PDF file.The code you see is inside a class which inherits from 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;
}

The method is triggered with a menu.
The problem is that the assertion fails:

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

Even if I declared the NSSavePanel pointer to be __block.Why?

Was it helpful?

Solution

Actually, the answer is to remove the __block specifier.

I ran your code with/without it. Assert is failing with it, working without it (the __blockspecifier, that is).

Now, to answer the why:

I suppose the __block specifier was made for global/instance variables, not local variables, I could be wrong though.


X'D ... I don't know what hit me, but check this:

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;

I just decided, let me wrap it in a GCD block, and draw it on the main thread. Your code is working splendidly. The view is being drawn to the PDF as expected, and I can confirm that :D.

As for the issue, it seems quite obvious. Calling bounds in a background thread and drawing is a no-no.

This was fun, thanks :D

OTHER TIPS

The solutions: for an unknown reason, which is still a mistery to me, if I make an IBAction to the view class, [self bounds] retuns always NSZeroRect.Inside other methods it returns the correct values.So I solved this problem removing the __block specifier from the NSSavePanel and rewriting (also re-binding) the method in the app delegate class.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top