478 Stimmen

Was bedeutet das Schlüsselwort "__block"?

Was genau bedeutet das __block Schlüsselwort in Objective-C? Ich weiß, dass es Ihnen ermöglicht, Variablen innerhalb von Blöcken zu ändern, aber ich möchte wissen...

  1. Was genau sagt es dem Compiler?
  2. Macht es noch etwas anderes?
  3. Wenn das alles ist, was es tut, warum wird es überhaupt benötigt?
  4. Steht es irgendwo in den Dokumenten? (Ich kann es nicht finden).

3 Stimmen

Überprüfen Sie hier und den Abschnitt "Blöcke und Variablen".

1 Stimmen

0 Stimmen

@Vincent danke, ich habe diesen Abschnitt vergessen! Ich werde es mir ansehen.

573voto

DarkDust Punkte 87647

Es sagt dem Compiler, dass jede Variable, die damit markiert ist, auf besondere Weise behandelt werden muss, wenn sie innerhalb eines Blocks verwendet wird. Normalerweise werden Variablen und deren Inhalte, die auch in Blöcken verwendet werden, kopiert, sodass Änderungen an diesen Variablen außerhalb des Blocks nicht sichtbar sind. Wenn sie mit __block markiert sind, sind die innerhalb des Blocks vorgenommenen Änderungen auch außerhalb davon sichtbar.

Beispiel und weitere Informationen finden Sie unter Der __block-Speichertyp in Apples Block-Programmierungsthemen.

Das wichtige Beispiel ist dieses:

extern NSInteger CounterGlobal;
static NSInteger CounterStatic;

{
    NSInteger localCounter = 42;
    __block char localCharacter;

    void (^aBlock)(void) = ^(void) {
        ++CounterGlobal;
        ++CounterStatic;
        CounterGlobal = localCounter; // localCounter bei Blockerstellung festgelegt
        localCharacter = 'a'; // setzt localCharacter im umgebenden Bereich
    };

    ++localCounter; // vom Block nicht gesehen
    localCharacter = 'b';

    aBlock(); // Block ausführen
    // localCharacter jetzt 'a'
}

In diesem Beispiel werden sowohl localCounter als auch localCharacter vor dem Aufruf des Blocks geändert. Innerhalb des Blocks wäre jedoch nur die Änderung an localCharacter sichtbar, dank des __block Schlüsselworts. Umgekehrt kann der Block localCharacter ändern und diese Änderung ist außerhalb des Blocks sichtbar.

12 Stimmen

Ausgezeichnete, präzise Erklärung und ein sehr hilfreiches Beispiel. Danke!

1 Stimmen

Wie verändert der aBlock den localCounter? Es scheint nur CounterGlobal zu verändern. Vielen Dank

8 Stimmen

Es ändert nicht localCounter, aber es ändert localCharacter. Achten Sie auch auf den Wert, den localCounter im Block hat: Es ist 42, obwohl die Variable vor dem Aufruf des Blocks, aber nach Erstellung des Blocks erhöht wird (da wurde der Wert "eingefangen").

30voto

Joe Punkte 56389

@bbum deckt in einem Blog-Beitrag ausführlich Blöcke ab und geht auf den __block-Speichertyp ein.

__block ist ein separater Speichertyp

Genau wie static, auto und volatile ist __block ein Speichertyp. Es sagt dem Compiler, dass der Speicher der Variablen anders verwaltet werden soll.

...

Allerdings behält der Block für __block-Variablen nicht. Es liegt an Ihnen, zu behalten und freizugeben, wie nötig.
...

Was die Anwendungsfälle betrifft, werden Sie feststellen, dass __block manchmal verwendet wird, um Rückhalteringszyklen zu vermeiden, da es das Argument nicht behält. Ein häufiges Beispiel ist die Verwendung von self.

//Now using myself inside a block will not 
//retain the value therefore breaking a
//possible retain cycle.
__block id myself = self;

0 Stimmen

Siehe diesen Beitrag für weitere Informationen zum Retain-Zyklus-Problem: benscheirman.com/2012/01/…. Würde __weak in diesem speziellen Fall auch ausreichen? Es ist vielleicht etwas klarer...

18 Stimmen

Schließlich ist die Behauptung, dass __block dazu verwendet werden kann, starke Referenzzyklen (auch als Haltezyklen bezeichnet) zu vermeiden, in einem ARC-Kontext schlicht falsch. Aufgrund der Tatsache, dass __block in ARC dazu führt, dass die Variable stark referenziert wird, ist es tatsächlich wahrscheinlicher, dass sie verursacht wird. stackoverflow.com/a/19228179/189006

16voto

Wenn Sie __block nicht verwenden, kopiert der Block die Variable (Call-by-Value), sodass der Block auch dann keine Änderungen sieht, wenn Sie die Variable an anderer Stelle ändern.

__block sorgt dafür, dass die Blöcke eine Referenz zur Variable behalten (Call-by-Reference).

NSString* str = @"hello";
void (^theBlock)() = ^void() {
    NSLog(@"%@", str);
};
str = @"wie geht es dir";
theBlock(); //gibt @"hello" aus

In diesen 2 Fällen benötigen Sie __block:

  1. Wenn Sie die Variable im Block ändern möchten und erwarten, dass die Änderung außerhalb sichtbar ist:

    __block NSString* str = @"hello";
    void (^theBlock)() = ^void() {
        str = @"wie geht es dir";
    };
    theBlock();
    NSLog(@"%@", str); //gibt "wie geht es dir" aus
  2. Wenn Sie die Variable ändern möchten, nachdem Sie den Block deklariert haben, und erwarten, dass der Block die Änderung sieht:

    __block NSString* str = @"hello";
    void (^theBlock)() = ^void() {
        NSLog(@"%@", str);
    };
    str = @"wie geht es dir";
    theBlock(); //gibt "wie geht es dir" aus

0 Stimmen

Ich werde auch erwähnen, dass eine automatische Variable, die mit __block markiert ist, vom Compiler in ein freigegebenes Objekt umgewandelt wird, dessen Lebensdauer so lange wie der Block ist, möglicherweise über den Bereich hinaus, in dem es deklariert ist. Darüber hinaus wird es jedes Mal erstellt, sodass jede Instanz des erstellten theBlock auf eine andere str-Variable verweisen wird.

11voto

Mindy Punkte 429

__block ist ein Speicherqualifizierer, der auf zwei Arten verwendet werden kann:

  1. Markiert, dass eine Variable in einem Speicherplatz lebt, der zwischen dem lexikalischen Bereich der ursprünglichen Variable und allen innerhalb dieses Bereichs deklarierten Blöcken gemeinsam genutzt wird. Und clang wird eine Struktur generieren, um diese Variable zu repräsentieren, und diese Struktur per Referenz (nicht per Wert) verwenden.

  2. In MRC kann __block verwendet werden, um zu vermeiden, dass Blockobjektvariablen behalten werden, die von einem Block erfasst werden. Achten Sie darauf, dass dies für ARC nicht funktioniert. In ARC sollten Sie stattdessen __weak verwenden.

Sie können sich auf apple doc für ausführliche Informationen beziehen.

7voto

__block ist ein Speichertyp, der verwendet wird, um Variablen im Bereich veränderlich zu machen. Genauer gesagt, wenn Sie eine Variable mit diesem Spezifizierer deklarieren, wird ihre Referenz an Blöcke übergeben, nicht eine schreibgeschützte Kopie. Weitere Details finden Sie unter Blocks Programming in iOS

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X