I got into the habit of coding my error handling this way:
NSError* error = nil;
NSDictionary *attribs = [[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error];
if (error != nil) {
DLogErr(@"Unable to remove file: error %@, %@", error, [error userInfo]);
return;
}
But looking at the documentation It seems like I got this wrong.:
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error
If an error occurs, upon return contains an NSError object that describes the problem. Pass NULL if you do not want error information.
Technically there is no difference between nil and NULL so does this mean I'm actually turning this off and will never get a error message (even if the delete in the above example did fail) ?
Is there a better way to code this ?
Thanks.
First off, the following line doesn't really make sense:
NSDictionary *attribs = [[NSFileManager defaultManager]
removeItemAtPath:fullPath error:&error];
-removeItemAtPath:error:
returns a BOOL value, not a dictionary.
I think I see what you’re wondering about with the NULL
value. Notice carefully though, how there are 2 *'s in the error parameter in the method signature:
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error
That means a pointer to a pointer. When you pass in &error
, you are passing in the address of the pointer to the NSError
. (Ugh, someone else can probably help me out here, as my head still starts to swim when dealing with pointers to pointers). In other words, even though you have set error
to nil
, you aren't passing in error
to the method, you're passing in &error
.
So, here’s what the re-written method should look like:
// If you want error detection:
NSError *error = nil;
if (![[NSFileManager defaultManager] removeItemAtPath:fullPath
error:&error]) {
NSLog(@"failed to remove item at path; error == %@", error);
// no need to log userInfo separately
return;
}
// If you don't:
if (![[NSFileManager defaultManager] removeItemAtPath:fullPath
error:NULL]) {
NSLog(@"failed to remove item at path");
return;
}
Passing NULL
means the following:
BOOL itemRemoved = [[NSFileManager defaultManager] removeItemAtPath:fullPath
error:NULL];
i.e., the error
parameter is NULL
. Internally, -removeItemAtPath:error:
sees if a valid pointer was passed. If it’s NULL
, it simply won’t report the error as an NSError
instance — but the return value will indicate whether the method completed successfully.
Also, your test is wrong. You shouldn’t be using the error
output parameter to detect if an error occurred because it might be set even if the method completes successfully. Instead, you should use the return value of the method to detect errors. If the return value (in this particular case) is NO
, then use the error
output parameter to get information about the error:
NSError *error = nil;
BOOL itemRemoved = [[NSFileManager defaultManager] removeItemAtPath:fullPath error:&error];
if (itemRemoved == NO) {
DLogErr(@"Unable to remove file: error %@, %@", error, [error userInfo]);
return;
}
Quoting the Error Handling Programming Guide,
Important: Success or failure is indicated by the return value of the method. Although Cocoa methods that indirectly return error objects in the Cocoa error domain are guaranteed to return such objects if the method indicates failure by directly returning nil or NO, you should always check that the return value is nil or NO before attempting to do anything with the NSError object.
Edit: As NSGod pointed out, -removeItemAtPath:error:
returns BOOL
, not NSDictionary *
. I’ve edited my answer to reflect that as well.
No I do it the same way and it works just fine for detecting errors. You are not passing NULL to it you are passing a pointer to NULL to it which is a very different thing. Although another option you might want to add is.
if (error != nil){...
}else{
[NSApp presentError:error]
}