David A
David A

Reputation: 46

How to avoid extensive error handling code on every layer in Objective C

In Objective C, how do I avoid having all this extensive error handling in my methods? I've read that Apple suggest that NSError references should be used only when errors are expected, but this approach causes the code to be completely cluttered with error handling code.

Apples guide to Exceptions

There is especially one sentence in this document that catches my eye;

a parsing library might use exceptions internally to indicate problems and enable a quick exit from a parsing state that could be deeply recursive; however, you should take care to catch such exceptions at the top level of the library and translate them into an appropriate return code or state

This is an (incomplete and unoptimized) snippet of code demonstrating what I mean. Every call I make within my method requires error checking on every step, cluttering the code with if statements and making it hard to read.

- (NSNumber) countFriendsForUserName:(NSString*) userName error:(NSError **)error {
    NSError *internalError = nil;
    Session *session = [_sessionMgr openSessionWithError:&internalError];
    if (!error) {
        User *user = [session findUserByName:userName error:&internalError];
       if (!error) {
           NSArray * bestFriends = [session getFriendsByUserId:user.id error:&internalError];
       }
    }
    [_sessionMgr closeSession];        
    if (internalError) {
        *error=internalError;
        return 0;
    } 
    return [bestFriends count];
}

If I were to use exceptions instead, the code would look something like this (again, this piece of code is just an incomplete example), I don't have XCode in front of me at the moment.

- (NSNumber) countFriendsForUserName:(NSString*) userName error:(NSError **)error {
    @try{
        Session *session = [_sessionMgr openSession];
        User *user = [session findUserByName:userName];
        NSArray * bestFriends = [session getFriendsByUserId:user.id];
        [_sessionMgr closeSession];  
        return [bestFriends count];            
    } 
    @catch (NSException *e) {
        [_sessionMgr closeSession];        
        *error=[ExceptionParser createNSErrorFromException:e];
        return 0;
    } 
}

If I interpret Apples Exceptions guidelines correctly, if my code is behaving like a "parsing library" (Apples example) it might be totally ok to use exceptions internally, and just translate them before I return to the calling function, which then in turn might act on my NSError codes to take appropriate action. Or have I misunderstood Apples guidelines?

Upvotes: 1

Views: 244

Answers (1)

Droppy
Droppy

Reputation: 9721

You should test the return value of the method, not the existence of the NSError object. Also you can chain the NSError objects to return the low-level error back to the caller:

- (NSInteger)countFriendsForUserName:(NSString*)userName
                               error:(NSError **)error
{
    NSArray *bestFriends = nil;
    Session *session = [_sessionMgr openSessionWithError:error];
    if (session) {
        User *user = [session findUserByName:userName error:error];
        if (user) {
           bestFriends = [session getFriendsByUserId:user.id error:error];
        }
    }
    [_sessionMgr closeSession];
    return [bestFriends count];
}

Note:

  • Moved bestFriends to the top of the method.
  • Changed return type.

Upvotes: 3

Related Questions