Using your example, the method signature would be:
-(BOOL)save:(NSError**)error;
Now, when using double pointers, you need to be defensive in your programming. First, you must make sure that the value of error
is not nil
, then *error
is nil
. You must do this because you don't know what to do memory management wise with an existing object. For example:
NSError *error = nil;
[self save:&error];
would be correct. But
NSError *error = [[NSError alloc] init];
[self save:&error];
is a problem because your save:
method won't if error
is retained
or autoreleased
. If you release
it and it's autoreleased
then your app will eventually crash. Conversely, if you don't release
it and it is retained
you leak memory. I recommend checking for this with an assert so that the problem is taken care of quickly before code is checked in.
NSAssert(!error || !*error, @"*error must be nil!");
Finally, when setting *error
you must make sure that error
is not nil
. You are never permitted to set the value of memory address 0x0
. If you don't check and if you pass nil
into the method, you will crash if you try to set it.
if (error)
{
*error = [NSError ...];
return NO;
}
To return an array I would do something like this:
-(BOOL)throwMultipleErrors:(NSError **) error {
NSAssert(!error | !*error, @"*error must be nil");
NSMutableArray *errorList = nil;
if (error)
errorList = [NSMutableArray array];
[errorList addObject:@"First Error"];
[errorList addObject:@"Second Error"];
[errorList addObject:@"Third Error"];
if (error && [errorList count] > 0)
{
*error = [NSError errorWithDomain:@"Some error"
code:0
userInfo:@{@"suberrors" : [NSArray arrayWithArray:errorList]}];
return NO;
}
return YES;
}
Note that the return array is immutable and is instantiated inside the method. There's really no reason for this array to be mutable outside of this method and for the array to be instantiated outside of it. Encapsulating the array in an NSError
permits it to easily fit into an existing chain of NSError
methods.
Notes
Of course, you would actually throw your [self save:&error];
call into an if()
statement to check the return value. Do note, however, that we pass in &error
rather than just error
. This is because we need to pass in the pointer to error
, not error
itself. &error
reads as "The address of error."