Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why is "error:&error" used here (objective-c)

why is "error:&error" used here (objective-c)

NSError *error = nil;
NSArray *array = [moc executeFetchRequest:request error:&error];

wouldn't an object in objective-c be effectively pass-by-reference anyway?

like image 403
Greg Avatar asked Nov 30 '11 23:11

Greg


People also ask

Why is error handling important?

Error handling helps in handling both hardware and software errors gracefully and helps execution to resume when interrupted. When it comes to error handling in software, either the programmer develops the necessary codes to handle errors or makes use of software tools to handle the errors.

Why is error handling important in Java?

Why handle Java exceptions? Java exception handling is important because it helps maintain the normal, desired flow of the program even when unexpected events occur. If Java exceptions are not handled, programs may crash or requests may fail.

How do you handle errors?

Do: Work on exceptions that directly impact the user experience. Don't: Build KPIs around reducing errors or exceptions by a certain percentage or targeting a specific number. Do: Prioritize errors related to your user's personal identifiable information, billing cycle, and functions that could corrupt your database.

What is JavaScript err?

js Way - Understanding Error-First Callbacks: The first argument of the callback is reserved for an error object. If an error occurred, it will be returned by the first err argument. The second argument of the callback is reserved for any successful response data.


2 Answers

The argument type for error: is NSError** (i.e. a pointer to a pointer to an object). This permits the moc object to allocate and initialize a new NSError object as required. It is a common pattern, especially in Cocoa.

The NSError documentation gives some indication of the motivation for this approach:

Applications may choose to create subclasses of NSError to provide better localized error strings by overriding localizedDescription.

Passing in an NSError** argument allows that method to return any subclass of NSError that makes sense. If you passed in NSError*, you would have to supply an existing NSError object, and there would be no way for the method to return a different object from the one you passed in.

To be clear, the method could look something like this:

- (NSArray*)executeFetchRequest:(Request *)request error:(NSError**)error {
    ...
    if ((error != NULL) && (some_error_condition)) {
        *error = [[[SomeNSErrorSubclass alloc] init...] autorelease];
        return nil;
    }
}

Note that this also allows the calling code to ignore errors by simply passing in NULL for the error: parameter, as follows:

NSArray *array = [moc executeFetchRequest:request error:NULL];

Update: (in response to questions):

There are two reasons why the argument type has to be NSError** instead of NSError*: 1. variable scoping rules, and 2. NSError instances are imutable.

Reason #1: variable scoping rules

Let's assume that the function declaration were to look like this:

- (NSArray*)executeFetchRequest:(Request *)request error:(NSError*)error;

And we were to call the function like this:

NSError * error = nil;
[someArray executeFetchRequest:someRequest error:error];
if (error != nil) { /* handle error */ }

When you pass in a variable this way, the function body will not be able to modify the value of that variable (i.e. the function body will not be able to create a new variable to replace the existing one). For example, the following variable assignments will exist only in the local scope of the function. The calling code will still see error == nil.

- (NSArray*)executeFetchRequest:(Request *)request error:(NSError*)error {
    ...
    error = [[[NSError alloc] init...] autorelease];             // local only
    error = [[[SomeNSErrorSubclass alloc] init...] autorelease]; // local only
}

Reason #2: instances of NSError are immutable

Let's keep the same function declaration, but call the function like this:

NSError * error = [[[NSError alloc] init...] autorelease];
[someArray executeFetchRequest:someRequest error:error];
if (error != nil) { /* handle error */ }

First of all, the variable scoping rules guarantee that error can not be nil, so the if (error != nil) { ... condition will always be true, but even if you wanted to check for specific error information inside the if block, you would be out of luck because instances of NSError are immutable. This means that once they are created, you cannot modify their properties, so the function would not be able to change the domain or userInfo of that NSError instance that you created in the calling code.

- (NSArray*)executeFetchRequest:(Request *)request error:(NSError*)error {
    ...
    error.domain = ...   // not allowed!
    error.userInfo = ... // not allowed!
}
like image 125
e.James Avatar answered Oct 23 '22 04:10

e.James


It's effectively another return value. The error is not dominant by convention in Cocoa when there is a return value for the operation. When an error is encountered, it may be returned to you by this out parameter.

In the case of NSError, it works this way because NSError is not a mutable type - its fields are set at initialization and never mutated. Therefore, you cannot pass an NSError as usual and set the error code.

like image 20
justin Avatar answered Oct 23 '22 06:10

justin