2

任意のブロックをリファクタリングするにはどうすればよいですか?

setenv()とunsetenv()はスレッドセーフであることが保証されていないため、スレッドセーフを確保できるように、署名が大きく異なる2つの関数をブロックとして渡します。

古いコード

-(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;
}

2つのコードチャンクは、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*) に変更し、非常に醜いキャストを行うと、これを機能させることができます。これが難読化してしまう場合は、ラッピング コードをコピーして貼り付ける必要があるかもしれません (yuck)。私は ObjC が大好きですが、ここでは C++ テンプレートのような機能が役に立ちます。より良い解決策がない場合は、この回答を受け入れます。tyvm! – kfmfe04

どうやら、ブロック外の変数にアクセスしたいので、キャストとリターンが必要です。それは簡単に治ります。

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