2

如何重构任意块?

我有两个签名截然不同的函数,我想将它们作为一个块传递,以便确保线程安全,因为 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() 的签名大不相同。

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

新代码

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

有什么方法可以在 Objective-C 中完成这种重构吗?

4

1 回答 1

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 包装建议。实际上,如果我将块签名更改为 return (void*) 并进行一些非常难看的转换,我可以让它工作。如果这最终导致混淆,我可能只需要复制粘贴包装代码(恶心)。我喜欢 ObjC,但这是一些像 C++ 模板这样的功能会派上用场的地方。如果没有更好的解决方案出现,我会接受这个答案。特维姆!– kfmfe04

显然,您需要强制转换并返回,因为您想访问块外的变量。这很容易补救。

__block X x;
[foo performWithMySpecialEnvironment:^{
    x = worker_1( ... );
}];
于 2012-10-23T21:13:27.883 回答