In a macOS programming project I have a command that allows the user to open a file containing some configuration options. This file is a property list, so the contents were being read using NSDictionary(contentsOf:); this method simply returns nil if an error occurs. I wanted to provide more details about the failure than simply “The file could not be read”, so I looked for a Foundation method that would throw an NSError. I settled on FileHandle(forReadingFrom:) and inserted the following code:
do {
_ = try FileHandle(forReadingFrom: url)
}
catch let error as NSError {
let alert = NSAlert()
alert.messageText = "An error occurred while reading the options file.".localized()
alert.informativeText = error.localizedDescription
alert.beginSheetModal(for: mainWindow) { (response) in
if response == NSAlertSecondButtonReturn {
OperationQueue.main.addOperation { self.resetOptions(nil) }
}
}
return
}
Then I set up a few test cases, including a file that was owned by another user (with no read permission). To my surprise, the error description implied that I was unable to write the file:

[application icon redacted]
…and while that’s also true, that’s certainly not the error I expected to get.
I looked at the error object in the debugger, and sure enough, the error code was 513 (NSFileWriteNoPermissionError) and not 257 (NSFileReadNoPermissionError). Weird.
Well, I know I’m trying to read the file, and I don’t want to confuse the user, so I changed the catch clause to handle this case:
catch var error as NSError {
if error.code == NSFileWriteNoPermissionError {
error = NSError(domain: NSCocoaErrorDomain, code: NSFileReadNoPermissionError, userInfo: error.userInfo)
}
let alert = NSAlert()
//...
return
}
…and that seemed to do nicely. But I can’t find any documentation on whether this is expected behavior or what I might be doing wrong.
Comments closed