如何处理Objective-C块中的任意签名?

时间:2012-10-23 20:56:16

标签: objective-c multithreading block

如何重构任意块?

我有两个函数具有截然不同的签名,我希望将其作为块传递,以便我可以确保线程安全,因为setenv()和unsetenv()不能保证是线程安全的:

旧代码

-(X*)foo1
{
  X* x;
  @synchronized( self )
  {
    setenv( ... );
    x = worker_1( ... );
    unsetenv( ... );
  }
  return x;
}

-(Y*)foo2
{
  Y* y;
  @synchronized( self )
  {
    setenv( ... );
    y = worker_2( ... );
    unsetenv( ... );
  }
  return y;
}

请注意,两个代码块是相同,除了worker_1()和worker_2()的签名有很大不同。

换句话说,我需要重构相同的包装,但完全不同的guts返回任意对象

新代码

- (void)aThreadSafeWrapper:my_block  // broken: needs fixing
{
    @synchronized( self )
    {
       setenv( ... );
       my_block();                   // broken: needs fixing
       unsetenv( ... );
    }
}

我有什么办法可以在Objective-C中完成这个重构吗?

1 个答案:

答案 0 :(得分:1)

我不知道我是否理解你的问题,但看起来你所需要的只是......

- (void)performWithMySpecialEnvironment:(void(^)(void))block
{
    @synchronized( self )
    {
       setenv( ... );
       block();
       unsetenv( ... );
    }
}

然后,你可以在你的街区做任何你想做的事......

[foo performWithMySpecialEnvironment:^{
    X x = worker_1( ... );
}];

[foo performWithMySpecialEnvironment:^{
    Y y = worker_2( ... );
}];

请注意,我并不支持@ synchronized / setenv / unsetenv用法,但由于这就是你正在做的事情,并且它不是手头真正问题的一部分,我会不理睬它,因为它可能会混淆真正的“阻塞”问题。

修改

  包装建议的

+1。实际上,如果我将块签名更改为返回(void *)并执行一些非常难看的转换,我可以得到   这个工作。如果这最终混淆,我可能只需要   复制粘贴包装代码(yuck)。我喜欢ObjC,但这就是我的地方   像C ++模板这样的功能会派上用场。我会   如果没有更好的解决方案,请接受此答案。 tyvm! - kfmfe04

显然,您需要进行转换和返回,因为您想要访问块外的变量。这很容易解决。

__block X x;
[foo performWithMySpecialEnvironment:^{
    x = worker_1( ... );
}];