2016-08-19 2 views
0

Die allgemeine Verwendung Muster NSError für das Bestehen wird mit Zeiger wie folgt Zeiger:Pointer Ausgabe über Objective-C-Objekte

- (id)doSomethingWithObj:(NSObject *)obj error:(NSError *__autoreleasing *)error 
{ 

    NSLog(@"error parameter: %p", error); 
    id object = obj; 
    if (object != nil) 
    { 
     return object; 
    } 
    else 
    { 
     NSError *tmp = [NSError errorWithDomain:@"after" code:0 userInfo:@{@"after": @"boris"}]; 
     *error = tmp; 
     return nil; 
    } 
} 

Ich weiß, dass die Adresse des außerhalb error Zeiger würde zuweisen oder ersetzen Sie den Ursprung seit Bestehen error, würde das obige Muster funktionieren.

Aber meine Frage über NSError oder allgemeinere, Objective-C Objekte, das ist, warum ich würde Fehler, wenn ich so geschrieben:

enter image description here

Statt NSError ** zu verwenden, habe ich versucht, NSError * und Was ich dachte ist, dass, da jetzt der Parameter error ein Typ von NSError * ist, also *error der Inhalt sein sollte, auf den der Zeiger (Fehler) zeigte, dann könnte *error = [NSError errorWith...]; den Ursprung außerhalb *error Inhalt ersetzen.

Aber es funktionierte nicht wie, was ich dachte, aber tauchte so oben Fehler auf.

Also, was mich verwirrt ist, warum *error = [NSError errorWith...]; nicht für den Typ von NSError * arbeitet aber für NSError ** arbeiten.

+1

Schnelle Anmerkung; Sie brauchen 'if (error) * error = tmp;'. I.e. Sie müssen überprüfen, ob "error" nicht-'nil' ist, bevor Sie es zuweisen. – bbum

Antwort

1

Wenn Sie einen Parameter in eine Methode übergeben wird kopiert und später in Ihrer Methode geht man mit dieser Kopie:

- (void)changeA:(NSInteger)aToChange { 
    aToChange = 7; 
} 

Dann, wenn Sie diese Methode verwenden, werden Sie nicht in der Lage sein, den Wert zu ändern Sie bestanden aus dem Inneren dieser Methode:

NSInteger a = 42; 
[smb changeA:a]; 
// a is still 42 

das, weil drin -changeA: Sie mit einer Kopie von Argumenten beschäftigen, das heißt, so dass Sie etwas tun, wie (Pseudocode):

// inside changeA: 
NSInteger aToChange = a; // (value is copied) 
aToChange = 7; // this does not modify a, right? 

Sie auch die Adresse dieser aToChange bekommen könnte und versuchen, etwas damit zu tun:

// inside changeA: 
NSInteger aToChange = a; // (value is copied) 
NSInteger *pointerToCOPY = &aToChange; // get address of aToChange 
NSInteger *pointerToA = &a; // get address of a 
// here pointerToCOPY != pointerToA 

Also, um Ihren Code zurück:

NSError *error = nil; // outer error, passed as a parameter 
... 
- (id)doSomethingWithObj:(NSObject *)obj error:(NSError *)error 
{ 
    // NSError *error(local copy) = error(passed argument); 
    error = tmp; // here error is the pointer to the local error copy 
    return nil; 
} 

Wie es zuvor mit aToChange war, Sie können Ihre externe NSError error * nicht von innerhalb Ihrer Methode ändern. Deshalb werden Doppelzeiger verwendet, Sie senden Zeiger auf Ihren Zeiger, so dass Sie immer noch Zugriff auf die externe error Referenz haben und sie einstellen können.

- (id)doSomethingWithObj:(NSObject *)obj error:(NSError **)error 
{ 
    // NSError **error(local copy) = error(passed argument); 
    *error = tmp; // Here *error is the pointer to the local error copy, 
    // When you dereference error you get NSError *, which you can set, 
    // that's your external error. 
    return nil; 
} 

Hinweis als es unmöglich ist, dies zu tun:

NSError *error = nil; 
NSError *otherError = [NSError error with]; 
*error = otherError; 

error ist ein Zeiger auf eine Struktur, ist *error eine Struktur, die mit einzelnem isa Feld (von dem Punkt des ID-Typ defenition). Es ist unangemessen, einer Struktur einen Zeiger auf den Fehler (otherError, d.h. die Plattformzeigergröße int) zuzuweisen.

Und dann die letzte Frage bleibt, warum nicht auch Sie:

NSError *error = nil; 
NSError *otherError = [NSError error with]; 
*error = *otherError; // why can't I assign to structs? 

Ich bin mir nicht ganz sicher, aber vielleicht Speicherverwaltung und ABI kommt im Spiel, hier könnte es nur Bündel kopieren von Bytes von einem Objekt zum anderen, da sie nur eine C-Struktur sind. Wie Sie wissen, ist Objective-C eine Obermenge von C, und es ist möglich, Strukturen dort zuzuordnen: Assign one struct to another in C. Das ist Objective-C-Besonderheit, die mit Objekten zu tun hat, denke ich. Alles ist ziemlich dynamisch, Sie können Klassen zur Laufzeit erstellen und Instanzvariablen hinzufügen (Mike Ash on that topic), daher ist zum Zeitpunkt der Kompilierung nicht bekannt, was über das Feld isa in der Struktur hinausgeht, und eigentlich ist id nur ein Zeiger auf diese Struktur mit einer einzigen isa. Das ist keine gute Idee, einfach das einzelne isa Struct kopieren und sagen, du bist fertig, Dinge werden auseinander fallen.

+0

@Avi ja, aber das sollte noch früher zur Kompilierzeit entdeckt werden, der Compiler darf dies nicht erlauben, da es unmöglich ist, einen Zeiger auf einen Fehler in eine Struktur umzuwandeln (objective c Object), sie sind inkompatibel. –