2012-11-13 5 views
5

Wenn ich über eine Objective-C-Methode verfüge, die einen Objektparameter verwendet und diese Methode intern einen Block verwendet, gibt es eine Möglichkeit, das Objekt innerhalb des Blocks zu ändern?Wie kann ich die Parameter einer ObjC-Methode innerhalb eines Blocks ändern?

Es ist mein Verständnis, dass Blöcke Variablen von ihrem übergeordneten Bereich erfassen, indem sie auf sie innerhalb des Blocks verweisen, und dass sie standardmäßig kopiert werden. Und wenn ich in der Lage sein möchte, mit einer Kopie eines umgebenden Objekts zu modifizieren, anstatt mit ihr zu arbeiten, kann ich ihre Deklaration mit __block voranstellen, aber ich kann dies nicht mit Methodenparametern tun, da ich sie nicht selbst deklariert habe, richtig?

Zum Beispiel:

- (void)doWorkWithString:(NSString *)someString 
{ 
    [NSFoo doAwesomeClassMethodWithBlock:^{ 
     // How can I modify someString here directly? 
     // By just changing someString, I'm changing the captured copy 
    }]; 
} 
+0

Ich bin zu faul, um die Dokumente nachschlagen, aber ich glaube nicht, dass gefangene Variablen zu einem Block kopiert werden; das wäre sehr überraschend, da Objekte keine Kopie implementieren können. Wenn __block nicht angegeben wird, werden die Objekte jedoch vom Block beibehalten. Innerhalb des Blocks unterscheiden sich Objektzeiger nicht anders als irgendwo sonst. Um Ihre Frage zu beantworten, können Sie sie beliebig modifizieren. Was Sie nicht tun können, ist in eine Variable zu schreiben, die erfasst wurde * IF * __block wurde nicht geliefert. Variablen, die mit __block markiert sind, werden vom Block nicht beibehalten. Seien Sie also vorsichtig. Hoffentlich macht das einen Sinn. –

+0

@darren: Nicht-Blockvariablen zu einem Block * werden * kopiert. Aber der Wert einer Variablen ist niemals ein Objekt. Sie können nur einen * Objektzeiger * haben. Wenn also ein Block einen Objektzeiger erfasst, kopiert er den Zeiger. Das hat absolut nichts mit dem Kopieren von Objekten zu tun. – newacct

+0

Ich meinte "Objektzeiger" -Parameter, wenn ich "Objektparameter" sagte. z.B. Übergeben einer NSString * -Instanz. –

Antwort

1

Was sagen Sie Capture korrekt ist; Was Sie wahrscheinlich tun möchten, ist, die Objekte, die Gegenstand des Blocks sein sollen, als Argumente zu liefern - ähnlich wie wenn Sie eine C-Funktion aufrufen würden. So z.B.

void (^ someBlock)(NSString *) = 
    ^(NSString *someString) 
    { 
     NSLog(@"length is %d", [someString length]); 
    }; 

... 

someBlock(@"String 1"); 
someBlock(@"A second string"); 
1

Ich erkannte, dass mein Kommentar oben war unglaublich verwirrend. Hoffentlich wird die folgende aufräumt, was ich versucht zu sagen:

- (void)yourMethod:(Foo *)parameterFoo 
{ 
    __block Foo *blockVariable = [Foo someFoo]; 
    Foo *capturedVariable = [Foo anotherFoo]; 

    void(^doWorkBlock)(Foo *bp) = ^(Foo *bp){ 
     // If your block accesses a scoped variable that is not marked with __block, it will 
     // retain it, so here capturedVariable and bp would be retained by the block 
     capturedVariable.aProperty = 5.0; 
     bp.aProperty = 10.0; 

     // As you can see, you can modify the objects all you like.   
     // What you cannot do is assign something to capturedVariable or bp because they 
     // were not marked as __block 
     // WONT WORK 
     capturedVariable = [Foo new]; 

     // However, you can write to blockVariable because it is marked as __block 
     // WORKS 
     blockVariable = [Foo new]; 
     // Remember, though that the block will not retain this variable itself because 
     // of the __block 
    }; 

    // Note, it's weird for the block to take a parameter since it could just access the 
    // variable directly. This just serves to show how a block would handle a parameter. 
    doWorkBlock(parameterFoo); 
} 
2

Zunächst einmal „die ein Objekt Parameter annimmt“, werden Sie mit ziemlicher Sicherheit durch die Tatsache verwirrt, dass Sie keine Parameter oder eine Variable haben des Objekttyps. Sie können nur Zeiger auf Objekte haben. Also ja, nicht __block Variablen, die von einem Block erfasst werden, werden vom Block kopiert. Aber die Variablen hier sind entweder Primitive oder Objektzeiger, keine "Objekte".

Wenn Sie nur das Objekt mutieren müssen, auf das ein Objektzeiger zeigt, und den Zeiger nicht auf einen anderen Punkt verweist, ändern Sie die Variable nicht. Und da Sie die Variable nicht ändern, ist all das "Kopieren der Variablen" und __block Zeug völlig irrelevant.