Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
583 views
in Technique[技术] by (71.8m points)

iphone - 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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!
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...