2012-11-27 3 views
11

Es wird in Apfels Dokumente gesagt: Ein Block-Literal (das heißt,^{...}) ist die Adresse von a Stapel-lokale Datenstruktur, die den Block darstellt. Der Umfang der Stapel lokale Datenstruktur ist daher die umschließenden zusammengesetzte Anweisung, so dass Sie die Muster in den folgenden Beispielen gezeigt vermeiden sollten:Ich weiß nicht, welche Muster von Block ich für den Literalbereich in objective-c vermeiden sollte

void dontDoThis() { 

    void (^blockArray[3])(void); // an array of 3 block references 

    for (int i = 0; i < 3; ++i) { 

     blockArray[i] = ^{ printf("hello, %d\n", i); }; 

     // WRONG: The block literal scope is the "for" loop. 
    } 

    //for example I invoke the block here 
    blockArray[1](); 
    } 


void dontDoThisEither() { 

    void (^block)(void); 

    int i = random(): 

    if (i > 1000) { 

     block = ^{ printf("got i at: %d\n", i); }; 

     // WRONG: The block literal scope is the "then" clause. 

    } 

    // ... 

    } 

Ich weiß nicht, welche Muster soll ich vermeiden. Es scheint so, als könnte ich den Block aufrufen, bei dem derselbe Literalbereich wie die Blockdefinition ist, zum Beispiel hinter der "if" - oder "for" -Anweisung. Könnten Sie mir bitte helfen, es zu erklären?

Hier ist es der Link https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Blocks/Articles/bxUsing.html#//apple_ref/doc/uid/TP40007502-CH5-SW1

Antwort

9

Ich denke, eine Analogie zu Zeiger, wie folgend.

void foo() { 
    int *block = NULL; 
    { 
    int a; 
    block = &a; 
    } 
    // `block`, even though defined here, points to 
    // an invalid memory address. 
} 

Im Allgemeinen wird der Block wörtliche selbst existiert nur in dem Block in definiert ist, so dass, wenn dieser Block zu verlassen, die wörtlichen verschwindet (wie die Variable a hatte im Beispiel oben), und Sie sind links mit ein baumelnder Zeiger.

Aus diesem Grund werden Blöcke normalerweise für zukünftige Verwendung in den Heap kopiert. Nicht-ARC-Code verwendet block_copy und Freunde. Beim Kopieren in den Heap werden auch alle relevanten Variablen erfasst, die Ihr Block verwendet (wodurch möglicherweise Aufbewahrungszyklen entstehen).

In der Praxis wird all dies durch die Verwendung von ARC, Eigenschaften und Klassen ziemlich gemieden. Sie definieren eine copy-Eigenschaft in Ihrer Klasse und weisen ihr dann Blöcke zu. Wenn Sie den Compiler den Getter/Setter generieren lassen, wird Ihr Blockliteral automatisch in den Heap kopiert.

@interface Bla : NSObject 
@property (nonatomic, copy) void (^blockProperty)(int i); 
@endf 

... 

Bla *bla = [[Bla alloc] init]; 
{ 
    bla.blockProperty = ^(int i) { printf("%d", i); }; 
} 
// bla.blockProperty now points to a heap copy of the block literal from above, 
// so it's not dangling. 
+0

Vielen Dank. Und heißt das, dass der Block als eine kopierte Eigenschaft deklariert werden sollte, anstatt als Stapelvariable in method? –

+0

oder kann ich einen Block als globale Variable deklarieren? Eigentlich sollte es auch im Local-Stack gespeichert sein, überall zu sehen. –

+0

Verstanden! Vielen Dank. Die Blockverbindungsanweisung mag einen ganzzahligen Wert im Wesentlichen als die Adresse einer stack-local-Datenstruktur. –

0

Ich las Apfels Dokumentation über Blöcke und machte ein wenig mehr Forschung zu diesem Teil. Es sieht für mich mit ARC das zweite Beispiel Code ist völlig in Ordnung. Ich habe das erste Beispiel nicht versucht. Die allgemeine Idee in der akzeptierten Antwort ist richtig. Wenn Sie jedoch den ARC-Block (NSStackBlock) einer lokalen Variablen zuweisen, wird der Block in den Heap kopiert. Wenn Sie den Block untersuchen, sehen Sie, dass es sich tatsächlich um einen NSMallocBlock handelt. Ich habe auch dieses Blog auf dieses Thema verwiesen https://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html