6

オブジェクト パラメーターを受け取る Objective-C メソッドがあり、そのメソッドがブロックを使用して内部的に作業を行う場合、ブロック内からそのオブジェクトを変更する方法はありますか?

ブロックは、ブロック内で変数を参照することによって親スコープから変数をキャプチャし、デフォルトでコピーされることを理解しています。また、周囲のオブジェクトのコピーを操作するのではなく変更できるようにしたい場合は、その宣言の前に を付けることができますが、__block自分で宣言していないため、メソッド パラメーターを使用することはできませんよね?

例えば:

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

3 に答える 3

2

「オブジェクトパラメータを取ります」

まず第一に、オブジェクト型のパラメーターまたは変数を持つことができないという事実に、ほぼ間違いなく混乱しています。オブジェクトへのポインターのみを持つことができます。そう__blockです、ブロックによってキャプチャされた非変数は、ブロックによってコピーされます。ただし、ここでの変数は、「オブジェクト」ではなく、プリミティブまたはオブジェクト ポインターです。

オブジェクト ポインターが指すオブジェクトのみを変更する必要があり、ポインターを別のオブジェクトを指すように変更する必要がない場合は、変数を変更していません。そして、変数を変更していないので、このすべての「変数のコピー」など__blockは完全に無関係です。

于 2012-11-13T09:45:35.987 に答える
1

上記のコメントが信じられないほど混乱していることに気付きました。うまくいけば、次のことで私が言おうとしていたことが明確になります。

- (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);
}
于 2012-11-13T06:26:58.203 に答える
1

キャプチャについてあなたの言うことは正しいです。おそらくやりたいことは、C 関数を呼び出す場合と同様に、ブロックの対象となるオブジェクトを引数として指定することです。だから例えば

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

...

someBlock(@"String 1");
someBlock(@"A second string");
于 2012-11-13T05:54:10.300 に答える