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."