Andrei Herford
Andrei Herford

Reputation: 18745

How to correctly handly NSError** pointers?

What is the correct way to handle NSError** pointers?

- (BOOL)handleData:(NSDictionary *)data error:(NSError **)error {
    // pass the error pointer to NSJSONSerialization
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:options error:error];

    // Check if NSJSONSerialization had errors
    if (error)  // <-- sometimes this works, sometimes it crashes...
       return false;

    ...

    return true;
}

- (void)someMethod {
    NSError *error = nil;
    BOOL result = [self handleData:dataDict error:&error]; 

    if (error) {
       // an error occurred
    } else {

    }
}

In this example someMethod passes a NSError reference to handleData:error. This is done by passing a pointer/address instead of the object (...error:&error)

The method handleData:error then passes this pointer to dataWithJSONObject:options:error (now without the &). Now I would like to check an error occurred, but what is the correct way to do this?

if (error)...   
// This works if error == nil. However this is not always the case. 
// Sometimes error is some address (e.g. 0x600001711f70) and *error == nil
// from the start of the method (passing error to NSJSONSerialization has no 
// influence on this

if (*error)...
// This works in cases where error itself is not nil, but it crashes if
// error == nil

Why is error == nil in some cases and error != nil but *error == nil in others?

What is the correct way to pass error between the methods and to check if an error occurred?

Upvotes: 1

Views: 967

Answers (1)

CRD
CRD

Reputation: 53010

The place to find the answers is Introduction to Error Handling Programming Guide For Cocoa. The conventions are:

  1. A method may return an NSError object via an NSError ** parameter, such a method should also have a non-void return type and indicate success or failure via its return value. So, using your example, dataWithJSONObject:options:error: will return nil if it encounters an error and may return an error object via its third parameter.

  2. Any method accepting an NSError ** parameter for error returns should accept either the address of an NSError * variable or NULL. The latter value means the user does not wish to have an error object returned. This means that the method accepting an NSError ** parameter must check the parameter value is not NULL before attempting to assign an error object via it.

So your method handleData:error: must be prepared to accept NULL and needs to test for it. Your code therefore must include something similar to:

// Check if NSJSONSerialization had errors
if (jsonData == nil)
{
   // Error occurred, did it return an error object?
   if (error != NULL && *error != nil)
   {
       // we have an error object
   }
   else
   {
      // we have an error but no error object describing it
   }
}
else
{
   // no JSON error
}

HTH

Upvotes: 4

Related Questions