beginSheetForDirectory:file:types:... Depreciated


I’m working through this chapter using Xcode 4.1 on Lion. When editing the AppController.m class on page 255 I’ve found that a significant amount of the code has been depreciated since 10.6 Snow Leopard. I think I’ve come up with a solution to work with the new code but I wanted to confirm that this has all that it needs to function as expected. Here’s the updated implementation (note the missing openPanelDidEnd:returnCode:contextInfo: method) -

#import “AppController.h”
#import “StretchView.h”

@implementation AppController

  • (IBAction)showOpenPanel:(id)sender
    NSOpenPanel *panel = [NSOpenPanel openPanel];

      //Run the open panel

    [panel setAllowedFileTypes:[NSImage imageFileTypes]];
    [panel beginSheetModalForWindow:[stretchView window] completionHandler:^(NSInteger result) {
    if (result == NSOKButton) {
    NSURL *path = [[panel URLs] objectAtIndex:0];
    NSImage *image = [[NSImage alloc] initWithContentsOfURL:path];
    [stretchView setImage:image];
    [image release];


I still don’t quite understand the completionHandler: part of the new beginSheetModalForWindow:completionHandler: method but I copied the style that Apple used in some of their examples in the documentation. I guess it just eliminates the need for a whole separate method for handling what happens after the panel closes?
You have to set the file types in a separate message ([panel setAllowedFileTypes:]) and Apple recommends that if you need to set the directory you can use setDirectoryURL: but I didn’t include it here since in the book, we just set it to nil.

Also note that the filename method when getting the path of the image is also depreciated. Apple suggests to use URLs instead. The problem with this is that it returns an NSArray * (because it allows for multiple selections). I fixed this by pulling out the first object in the array. You get it as a NSURL though (instead of NSString in the book) so *path just needs to be a NSURL. Consequently, in the very next line you need to init the image as initWithContentsOfURL: instead of …ContentsOfPath:.

In Apple’s example they check for the OK button by if (NSFileHandlingPanelOKButton == result) but the form in the Cocoa book if (result == NSOKButton) seems to work just fine. What’s the difference?

EDIT: Never mind, I see that they are exactly the same; per Apple’s documentation: enum { NSFileHandlingPanelCancelButton = NSCancelButton, NSFileHandlingPanelOKButton = NSOKButton };

Thoughts? Suggestions? I mainly posted this to see if I’ve got everything I need covered using the new format but hopefully this can help someone else who’s been wondering how to move away from the depreciated methods.


I did much the same as you with 2 main differences.
I set attributes to the panel when I initialised it, so that it could only accept a single file - this eliminated the need to extract the first image file from the array.
And I embedded the processing in a separate block inside the method. For me, this just makes it easier to read but it is functionally identical.

[code]- (IBAction)showOpenPanel:(id)sender
// 1. Initialize and configure the panel
NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setAllowedFileTypes:[NSImage imageFileTypes]];
[panel setCanChooseDirectories:NO];
[panel setAllowsMultipleSelection:NO];

// 2. Set up the block function to process the selection
void (^imageOpenPanelHandler)(NSInteger) = ^( NSInteger result )
	if( NSFileHandlingPanelOKButton == result )
        NSURL *imageURL = [panel URL];
        NSImage *image = [[NSImage alloc] initWithContentsOfURL];
        [stretchView setImage:image];
        [image release];

// 3. Open the panel
[panel beginSheetModalForWindow:[stretchView window] 

Note the order in which things must be done to allow this to work (I have number the comments).
The panel must be declared and configured before the processing block or the block will not be able to access the panel.
The processing block must come before the panel is opened, or the panel will not be able to find it.