Warum benötigt NSError eine doppelte Indirektion? (Zeiger auf einen Zeiger)

Lesezeit: 5 Minuten

Dieses Konzept scheint mich zu beunruhigen. Warum muss der Zeiger eines NSError-Objekts an eine Methode übergeben werden, die das Objekt ändert? Würde zum Beispiel nicht einfach ein Verweis auf den Fehler übergeben werden?

NSError *anError;
[myObjc doStuff:withAnotherObj error:error];

und dann in doStuff:

 - (void)doStuff:(id)withAnotherObjc error:(NSError *)error 
 {
    // something went bad!
    [error doSomethingToTheObject];
 }

Warum funktioniert das obige nicht wie die meisten anderen Objektnachrichtenmuster? Warum müssen wir stattdessen error:(NSError **)error verwenden?

Recht einfach:

Wenn Sie Ihrer Funktion einen Zeiger auf ein Objekt übergeben, kann die Funktion nur ändern, worauf der Zeiger zeigt.

Wenn Sie einen Zeiger an einen Zeiger auf ein Objekt übergeben, kann die Funktion den Zeiger so ändern, dass er auf ein anderes Objekt zeigt.

Im Fall von NSError möchte die Funktion möglicherweise ein neues NSError-Objekt erstellen und Ihnen einen Zeiger auf dieses NSError-Objekt zurückgeben. Daher benötigen Sie eine doppelte Indirektion, damit der Zeiger geändert werden kann.

  • Das hilft mir wirklich zu verstehen. Ich bin daran gewöhnt, im Kontext von Sprachen an Zeiger zu denken, die zwischen den Argumenten “byref” und “byval” unterscheiden. Byref-Argumente (dh Variablen, auf die durch Zeiger verwiesen wird) können von der aufgerufenen Funktion geändert werden, und der Aufrufer kann die Änderung sehen, daher habe ich die Antwort von @ n8gray nicht verstanden: “Wenn Sie nur eine NSError*doStuff würde das Fehlerobjekt niemals an seinen Aufrufer zurückgeben können”. Ihre Antwort “Die Funktion kann den Zeiger so ändern, dass er auf ein anderes Objekt zeigt” macht deutlich, WARUM Sie das möchten ** wenn der Anrufer bereits Änderungen mit nur einem Zeiger sehen kann.

    – steif

    15. August 2011 um 20:45 Uhr


  • Das macht Sinn, aber warum nicht einfach ändern, worauf der Zeiger zeigt?

    – Will Gwo

    25. Juli 2018 um 0:21 Uhr

Benutzeravatar von n8gray
n8grau

Das NSError** Muster wird verwendet, wenn eine Methode normalerweise einen Wert zurückgibt, stattdessen aber möglicherweise ein Fehlerobjekt (vom Typ NSError*) falls es schief geht. In Objective-C kann eine Methode nur einen Objekttyp zurückgeben, aber in diesem Fall möchten Sie zwei zurückgeben. Wenn Sie in C-ähnlichen Sprachen einen zusätzlichen Wert zurückgeben müssen, fragen Sie nach einem Zeiger auf einen Wert dieses Typs, also um an zurückzugeben NSError* du brauchst ein NSError** Parameter. Ein realistischeres Beispiel wäre dieses:

// The method should return something, because otherwise it could just return
// NSError* directly and the error argument wouldn't be necessary
- (NSArray *)doStuffWithObject:(id)obj error:(NSError **)error
{
  NSArray *result = ...;  // Do some work that might fail
  if (result != nil) {
    return result;
  } else {
    // Something went bad!
    // The caller might pass NULL for `error` if they don't care about
    // the result, so check for NULL before dereferencing it
    if (error != NULL) {
      *error = [NSError errorWithDomain:...];
    }
    return nil;  // The caller knows to check error if I return nil
  }
}

Wenn du nur einen hättest NSError* Parameter statt an NSError** dann doStuff niemals in der Lage wäre, das Fehlerobjekt an seinen Aufrufer zurückzugeben.

Eine alte Frage, aber ich denke trotzdem, dass es sich lohnt, sie hier zu stellen –

Der eigentliche Schuldige ist NSFehler. Wenn Sie sich seine Klassenreferenz ansehen, gibt es keine Setter-Methoden für eines seiner Attribute, dh domain, code oder userInfo. Es gibt also keine Möglichkeit, Sie können einfach einen NSError zuweisen und initialisieren, ihn an die Methode übergeben und dann Informationen zum übergebenen NSError-Objekt füllen. (Hätte es eine Setter-Methode gegeben, hätten wir einfach einen NSError * übergeben und so etwas wie error.code = 1 in der Methode tun können.)

Falls also ein Fehler auftritt, müssen Sie ein neues NSError-Objekt in der Methode generieren, und wenn Sie dies tun, können Sie es nur mit einem NSError ** -Argument an den Aufrufer zurückgeben. (Aus dem in den obigen Antworten erläuterten Grund.)

Alternative Aussage zu dem, was n8gray gesagt hat:

Weil Sie kein Objekt erhalten, an das Sie Nachrichten senden können; Sie erstellen das Objekt und geben es zurück. Sie benötigen im Allgemeinen den Zeiger auf einNSError *-variable Argument, weil Sie nur die verwenden können return Aussage zu einer Sache zu einer Zeit, und Sie verwenden es bereits mit NO.

Benutzeravatar von Smart Home
Intelligentes Zuhause

Ich habe immer noch nicht das vollständige Bild erhalten, indem ich alle Antworten oben gelesen habe. Die Laienübung, die ich unten gemacht habe, hat mir endlich geholfen zu verstehen, was passiert. Stell es einfach raus, falls es anderen Anfängern hilft.

Angenommen, Sie haben folgendes

@interface Class X
-(void) methodX:(NSMutableArray *)array;
@end

In einem anderen Teil des Codes haben Sie die folgende Sequenz

ClassX *objectX = [[ClassX alloc] init];
NSMutableArray *arrayXX = [@[@(1), @(2)] mutableCopy]; 
//What is stored in arrayXX is the address in the heap at which the NSMutableArray object starts, lets call this address ZZZ
//array starting at address ZZZ in the heap now contains NSNUmbers @1,@2
[objectX methodX:array]

Wenn Sie aufrufen [objectX methodX:array]was von der Methode empfangen wird, ist a Kopieren von array. Da Array eine Adresse enthält (dh ein Zeiger ist), ist die Kopieren ist insofern etwas Besonderes, als eine weitere Variable mit der Adresse ZZZ darin empfangen wird.

Also, wenn MethodeX dies tut [array removeObjectAtIndex:0], dann wird das Objekt ab Adresse ZZZ betroffen (enthält jetzt nur noch einen NSNUMber @(2)). Wenn die Methode zurückkehrt, wird also auch das ursprüngliche Array beeinflusst.

Nehmen wir stattdessen an, dass methodX dies tut array = [@[@(2)] mutableCopy]; dann wird das ursprüngliche Array nicht beeinflusst. Dies liegt daran, dass Sie nicht in die Adresse ZZZ gegangen sind und etwas geändert haben. Stattdessen überschrieben Sie die ZZZ in der Kopieren von der Methode an eine andere Adresse YYY empfangen. Die YYY-Adresse ist der Beginn eines NSMUtableArray-Objekts mit einem Element NSNUMber @(2). Die ursprüngliche ZZZ-Adresse enthält noch ein NSMUtableArray mit zwei Elementen. @(1) und @(2). Wenn die Methode zurückkehrt, ist das ursprüngliche Array also nicht betroffen.

1407690cookie-checkWarum benötigt NSError eine doppelte Indirektion? (Zeiger auf einen Zeiger)

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy