如何在块中修改ObjC方法的参数?

时间:2012-11-13 05:09:47

标签: objective-c block

如果我有一个Objective-C方法接受一个object参数,并且所述方法使用一个块在内部完成它的工作,有没有办法从块中修改该对象?

据我所知,块通过在块中引用变量来捕获变量,并且默认情况下会复制它们。如果我想能够修改而不是使用周围对象的副本,我可以用__block作为声明的前缀,但我不能用方法参数这样做,因为我没有声明它我自己,对吧?

例如:

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

3 个答案:

答案 0 :(得分:2)

“采用对象参数”

首先,您几乎肯定会因为您不能拥有对象类型的参数或变量而感到困惑。您只能指向对象。所以,是的,块阻止了块捕获的非__block变量。但这里的变量是基元或对象指针,而不是“对象”。

如果您只需要改变对象指针所指向的对象,并且不涉及将指针更改为指向另一个对象,那么您不会更改该变量。由于您没有更改变量,所有这些“复制变量”和__block内容完全无关。

答案 1 :(得分:1)

你对捕获的看法是正确的;您可能想要做的是提供应该作为块的主题的对象作为它的参数 - 就像您调用C函数一样。例如,

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

...

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

答案 2 :(得分: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);
}