35

I'ver wondered, why is it that in front of an NSError, such as below, do we put: &error and not error?

E.g.

NSArray *result = [managedObjectContext executeFetchRequest:fetchRequest error:&error];

Hope you can explain, also is this always the way or only in certain situations this is needed? Thanks.

Josh Kahane
  • 16,765
  • 45
  • 140
  • 253
  • 1
    This is *standard* C pointers... the *unary* `&` operator is the "address of" operator. Lots of good reading and *tutorials* on the subject, and a few keywords in the previous sentence. –  Apr 07 '12 at 23:37
  • 1
    possible duplicate of [Pointers in C: when to use the ampersand and the asterisk](http://stackoverflow.com/questions/2094666/pointers-in-c-when-to-use-the-ampersand-and-the-asterisk) –  Apr 07 '12 at 23:42
  • @user166390 Oh man you're smart!! – user3932000 Apr 13 '17 at 23:29

3 Answers3

63

You need to take the address of error because the function needs to modify it. error is passed by pointer, so you need the "take address" operator & for it.

C and Objective-C pass parameters by value. If you pass error without an ampersand and the method that you call modifies it, your function that made the call would not see any changes, because the method would operate on its local copy of NSError*.

You know that you need an ampersand in front of the corresponding parameter if you look at the signature of the method and see ** there:

- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError **)error
                                            //   ^ one                    ^^ two
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
8

The error parameter's type is (NSError **), that is a pointer to a pointer to an NSError. The error variable that you use as the argument is probably declared as NSError *, so in order to get the types to match properly, you have to use the address of operator to get a pointer to a pointer (&error). The reason the method needs a pointer to a pointer in the first place is so that it can modify the value of error and have that new value be available to you, the caller of the method.

UIAdam
  • 5,303
  • 1
  • 27
  • 23
7

Essentially, the root of the issue is a hack for wanting to return a second (optional) object.

How can we do this, as we can only return one thing? Well, we could return some sort of (return_value, error) tuple, but that's a bit unwieldy. We can have as many parameters as we like though, can we do something with those...

So, methods/functions can't modify their parameters (to be precise, they operate with a copy, so any modifications they make are local). That is to say (concurrency issues aside) the value of fetchRequest before the message in your question will be equal to the value of fetchRequest afterwards. Note the object pointed to by fetchRequest might change, but the value of fetchRequest itself won't.

This puts us in a bit of a bind. Except, wait, we know we can happily take the value of a parameter and modify what it points to! If you look at the declaration for executeFetchRequest:error: you'll see it takes an NSError**. That's "a pointer to a pointer to an NSError". So, we can initialise an empty/dangling NSError*, find the address of it (with the unary & operator), and pass that in. The method can then assign to the NSError* pointed to by this.

Voila, we effectively have optional additional return values.

Kristian Glass
  • 37,325
  • 7
  • 45
  • 73
  • Thanks for the explanation. I believe I ALMOST understand it. I understand a local copy of fetchRequest is made in the method in order to work so the original fetchRequest will remain unchanged. But why then does the object pointed to by fetchRequest change but the value of fetchRequest doesnt? – marciokoko Aug 17 '13 at 15:23
  • Try this analogy: I tell you to "count the files in box 3 over there and tell me how many there are". I'm the caller, and I've given you a pointer. You can now do whatever you like to the contents of box 3 (modify the object at the pointer you've given), and you can even decide you're going to ignore what I told you and look at box 2, but none of that affects the value of what I gave you (the caller's context) – Kristian Glass Aug 18 '13 at 13:39
  • Yep, in Swift you can return a tuple that contains the normal return type plus an Error that could be nil. – CommaToast Feb 08 '16 at 21:50