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

时间:2022-09-07 11:04:55

How do I refactor arbitrary blocks?

我如何重构任意块?

I have two functions with vastly different signatures that I would like to pass as a block so that I can ensure thread-safety, since setenv() and unsetenv() are not guaranteed to be thread-safe:

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

Old Code

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

Note that the two chunks of code are identical except that the signatures to worker_1() and worker_2() are vastly different.

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

In other words, I need to refactor the same wrappers, but completely different guts returning arbitrary objects.

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

New Code

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

Is there any way I can accomplish this refactoring in Objective-C?

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

1 个解决方案

#1


1  

I don't know if I understand your question, but it looks like all you need is something like...

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

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

Then, you can do whatever you want in your block...

然后,你可以在你的块中做任何你想做的事......

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

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

Note, that I do not endorse the @synchronized/setenv/unsetenv usage, but since that's what you are doing, and it's not part of the real question at hand, I'll leave it alone since it may just confuse the real "blocks" issue.

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

EDIT

+1 for the wrapper suggestion. Actually, if I change the block signature to return (void*) and do some really ugly casting, I can get this to work. If this ends up obfuscating, I may just have to copy-paste the wrapping code (yuck). I love ObjC, but this is where some functionality like C++ templates would come in handy. I will accept this answer if no better solution comes along. tyvm! – kfmfe04

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

Apparently, you need the casting and return because you want to access the variable outside the block. That's easily remedied.

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

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

#1


1  

I don't know if I understand your question, but it looks like all you need is something like...

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

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

Then, you can do whatever you want in your block...

然后,你可以在你的块中做任何你想做的事......

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

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

Note, that I do not endorse the @synchronized/setenv/unsetenv usage, but since that's what you are doing, and it's not part of the real question at hand, I'll leave it alone since it may just confuse the real "blocks" issue.

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

EDIT

+1 for the wrapper suggestion. Actually, if I change the block signature to return (void*) and do some really ugly casting, I can get this to work. If this ends up obfuscating, I may just have to copy-paste the wrapping code (yuck). I love ObjC, but this is where some functionality like C++ templates would come in handy. I will accept this answer if no better solution comes along. tyvm! – kfmfe04

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

Apparently, you need the casting and return because you want to access the variable outside the block. That's easily remedied.

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

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