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

您所说的捕获是正确的;你可能想要做的是提供应该作为块主题的对象作为它的参数——就像你调用一个 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 回答
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 回答