I’ve just spent hours and hours tracking down a sporadic error in my sandboxed application where the user would occasionally report not being able to open files from an Open Files dialog.
The Symptoms
The first time the user selects a file it always works, however, if they tried to open a different file then [NSFileHandle fileHandleForReadingFromURL:error:]
would return nil
. Dumping out the contents of the NSError
, I could see:
Unable to open file: Error Domain=NSCocoaErrorDomain Code=1 "The operation couldn’t be completed. (Cocoa error 1.)" UserInfo=0x608000072740 {NSFilePath=/Users/edwardsc/myfile.txt}
I’ve seen this error before when I first sandboxed my app and, sure enough, /var/log/system.log
reports:
MyApp(2811) deny file-read-data /Users/edwardsc/myfile.txt
What puzzled me was why it only happened on the second file. My application definitely has the com.apple.security.files.user-selected.read-write
entitlement defined (and the first open file actually works).
The Solution
It turns out that the problem was that I was re-using my instance of NSOpenPanel
. My view controller had an @property
that referenced the NSOpenPanel
, and my code basically looked like:
if (self.importOpenPanel == nil) self.importOpenPanel = [NSOpenPanel openPanel]; [self.importOpenPanel setDelegate:self]; [self.importOpenPanel setAllowsMultipleSelection:YES]; [self.importOpenPanel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) { // do some stuff here }];
So, basically I was re-using the NSOpenPanel
instance after the first time. If I create a new instance of NSOpenPanel
each time, it works perfectly.
Maybe there is some Apple documentation somewhere that says not to do re-use a NSOpenPanel
, however, I thought I’d post this as the symptoms are pretty non-obvious and I may be able to save someone the pain I just went through.
Note: Interestingly, if you re-use the NSOpenPanel
but happen to choose the first file again, it will actually work. I can vaguely rationalise that to myself but the whole thing is a little counter-intuitive.