2010-07-15 32 views
36

Ich dachte nur, wie Sie Blocks wie Objekte behandeln können, wenn ich zwei von ihnen erstellen und sie dann zu einem NSArray hinzufügen gibt es eine Möglichkeit, sie aus dem Array auszuführen?Ausführen von Blöcken von NSArray?

int (^Block_001)(void) = ^{ return 101; }; 
int (^Block_002)(void) = ^{ return 202; }; 
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil]; 

EDIT: Update für Klarheit Pro @ davedelong die ausgezeichnete Antwort

int (^Block_001)(void) = [^{ return 101; } copy]; 
int (^Block_002)(void) = [^{ return 202; } copy]; 
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil]; 

[Block_001 release]; 
[Block_002 release]; 
+2

Schöne Reihe von Antworten .... Ich sah den Titel und hoffte auf einige einfache Rep-Punkte. Leute haben es ziemlich gründlich abgedeckt. :) – bbum

+0

Nur ein kurzer Punkt, wenn du den Block nicht kopierst/frei gibst, wird er im Stack sein ... Wenn also der Stack zerstört wird, stürzt die App richtig ab? – fzaziz

Antwort

29

Sicher, Sie rufen Sie es einfach mit () wie jeder andere Block, aber Sie müssen den Wert, den Sie von NSArray abrufen typisieren. Hier ist ein Beispiel (mit einem zusätzlichen typedef, weil sonst mein Kopf tut weh):

typedef int (^IntBlock)(void); 
IntBlock Block_001 = ^{ return 101; }; 
IntBlock Block_002 = ^{ return 202; }; 
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil]; 
int x = ((IntBlock)[array objectAtIndex:0])(); // now x == 101 
+0

ok, also nicht mit Funktionszeigern vertraut bin ich das richtig? Der typedef definiert "IntBlock", das ein Zeiger auf einen Block ist, der ein int zurückgibt und keine Argumente annimmt. Ich denke, dass ich es verstehe, und schaue auf die Alternative (die ich ziemlich sicher bin, dass ich falsch liege). Ich schätze deine Entscheidung, mit der Typedef zu gehen :) Sehr geschätzt. – fuzzygoat

+0

Ja, du hast es. –

+1

Sie müssen es nicht umwandeln. Es funktioniert gut, um 'int (^ block)() = [array objectAtIndex: 0]' zu tun. Ein Pointer ist immerhin ein Pointer, immerhin ein Pointer, zumindest in Low-Level-Sprachen wie 'C' und seinen Ableitungen. – aroth

6

Natürlich können Sie.

int (^x)(void) = [array objectAtIndex:0]; 
printf("%d\n", x()); // prints 101. 
+0

Ich fand das sehr interessant. Kannst du nur für mich klären, habe ich recht damit, auf "int (^ x) (void)" als Zeiger auf einen Block zu verweisen? Ich versuche nur, dass ich die Terminologie korrekt finde. – fuzzygoat

60

@KennyTM und @ David korrekt ist, aber Ihr Code ist möglicherweise falsch. Hier ist warum:

Bei der Erstellung eines NSArray mit Objekten, wird es retain die Objekte hineingelegt. Im Fall von Blöcken wird die Block_retain-Funktion verwendet. Das bedeutet, dass das Array die von Ihnen erstellten Blöcke beibehalten hat, aber , die auf dem Stapel liegen (Blöcke sind eines der sehr seltenen Beispiele für Objective-C-Objekte, die auf dem Stapel erstellt werden können, ohne in absurde Tricks zu verfallen). Das bedeutet, dass Ihr Array jetzt, wenn diese Methode beendet wird, auf Garbage verweist, da die Blöcke, auf die es auf zeigte, nicht mehr existieren. Richtig machen dies, sollten Sie tun:

int (^Block_001)(void) = [^{ return 101; } copy]; 
int (^Block_002)(void) = [^{ return 202; } copy]; 
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil]; 

[Block_001 release]; 
[Block_002 release]; 

Durch copy Aufruf auf dem Block, werden Sie explizit Bewegen des Blocks von dem Stapel und auf dem Heap, wo es sicher, nachdem die Methode/Funktion beendet bleiben können . Dann, nachdem Sie die Blöcke zum Array hinzugefügt haben, müssen Sie Ihre copy (wegen der NARC-Regel) mit einem nachfolgenden Aufruf an release ausgleichen. Sinn ergeben?

+0

Hallo Dave, ja, ich verstehe, ich war mir nicht bewusst, dass Blöcke auf dem Stapel erstellt werden (erst jetzt begann man Blöcke zu betrachten). Sehr geschätzt. – fuzzygoat

+0

Hervorragender Punkt auf der Notwendigkeit zu kopieren –

+0

Hallo Dave, ich fand diese Frage und David Gelhar's akzeptierte Antwort, also implementierte ich es und es funktionierte ganz gut, es ** stürzte nicht ab. Wenn du weiter liest, hat deine Antwort einen Sinn ergeben, aber nicht erklären, warum Davids Code nicht abstürzt (sofort?). Hast du eine Ahnung? – Tieme

Verwandte Themen