2016-08-02 17 views
1

ich froh sein würde Erklärung für das folgende Verhalten zu erhalten:A Tricky Objective-C-Blöcke Verhalten

typedef void (^MyBlock)(void); 
MyBlock g_ary[4]; 

int runBlockParam2(MyBlock callbackBlock, int num) { 
    g_ary[num] = callbackBlock; 
    return num+100; 
} 

int main(int argc, const char * argv[]) { 
    @autoreleasepool { 
     int i; 
     for (i=0; i<4; i++) { 
      __block int j; 
      int k = runBlockParam2(^{ 
       NSLog(@"in the block i=%i, j=%i", i, j); 
      }, i); 
      j=k; 
     } 
     for (i=0; i<4; i++) { 
      g_ary[i](); 
     } 
    } 
    return 0; 
} 

Der obige Code zeigt die folgende Ausgabe: in the block i=0, j=100 in the block i=1, j=101 in the block i=2, j=102 in the block i=3, j=103

Warum j durch die modifiziert Zuordnung, die dem Block folgt?

Es ist interessant zu erwähnen, dass, wenn wir den __block Modifikator entfernen, werden wir diese: in the block i=0, j=0 in the block i=1, j=100 in the block i=2, j=101 in the block i=3, j=102

Ich werde eine Erklärung auf das oben beschriebene Verhalten schätzen!

Antwort

3

Der Speichertyp __block bewirkt, dass Änderungen an der Variablen außerhalb des Blocks innerhalb des Blocks angezeigt werden und umgekehrt. Ihre Zeile j = k wird ausgeführt, bevor der Block selbst in Ihrer zweiten for-Schleife ausgeführt wird, sodass der Block nach der Zuweisung j angezeigt wird.

Das Entfernen der __block bewirkt, dass der Block den Wert j so erfasst, wie er ist, wenn der Block erstellt wird, der vor der Zuweisung liegt. Sie Aufruf nicht definiertes Verhalten nach dem __block entfernen, weil Sie j aufnimmst, bevor es initialisiert wurde, das zu dem seltsamen Ausgang führt. Wenn Sie Ihre Deklaration in int j = 0 ändern, würden die Protokollanweisungen alle j=0 anzeigen, wie Sie es erwarten würden.

+0

Vielen Dank für die Antwort. Aber 'j 'geht in den nächsten Zyklen weiter, also warum werden sie nicht alle 103, als der letzte Wert, der' j 'zugewiesen wird, bevor der Gültigkeitsbereich der' j'-Variable verlassen wird? – ishahak

+0

Sie deklarieren 'j' innerhalb der Schleife, so dass jeder Block sein eigenes' j' hat, auf das es sich bezieht. Wenn Sie den '__block int j;' außerhalb der Schleife verschieben, werden alle Blöcke 'j = 103' ausgeben. – dan

+0

Danke @dan. Ich werde deine Antwort akzeptieren. Das bedeutet, dass eine Variable '__block' eigentlich eine statische Variable innerhalb des Blocks ist, aber solange der Umfang ihrer Deklaration existiert, kann sie außerhalb des Blocks aufgerufen werden! – ishahak

0

mit __block wird die j-Variable als Zeiger in Block übergeben. Wenn Sie also den Block nach der Zuweisung aufrufen, ist 0 jetzt j=k j 100.

ohne __block nur der Wert des j Variable wird in den Block übergeben. Block selbst konnte j nach der Blockdefinition, in der der Wert übergeben wird, nicht ändern. so j 0