2

これは少しトリッキーなシナリオです。ブロックを勉強していて初めて実装するようになったのですが、「複合ブロック」を作りたいと思っていました。これが私のコードです。

- (void)moveToPosition:(NSInteger)pos withVelocity:(CGFloat)vel onCompletion:(void(^)(BOOL completed))completionBlock
{

    void (^compoundBlock) (BOOL completed) = ^(BOOL completed) {
        [self unlockInteractionFromPullDownMenuTab];
        void(^innerCompletionBlock)(BOOL completed) = completionBlock;
        innerCompletionBlock(completed);
    };

    // Animate
    [UIView animateWithDuration: duration
                     animations: ^void{ [self.pullDownMenu setFrame:newFrame]; }
                     completion: compoundBlock
     ];


}

目標は、このメソッドに渡されるコードのブロックを取得し、それに何かを追加してから、アニメーション メソッド呼び出しに渡すことです。ただし、次の行でアクセスがうまくいきません。

innerCompletionBlock(completed);

innerCompletionBlock の割り当てが解除されていると思いますが、その理由は完全にはわかりません。私が理解していることから、ブロックは、self への参照を含め、スローされたすべてのものをコピーします。

実際、私はもともとこれを試しました:

void (^compoundBlock) (BOOL completed) = ^(BOOL completed) {
    [self unlockInteractionFromPullDownMenuTab];
    completionBlock(completed);
};

しかし、私はアクセスが悪く、おそらくcompoundBlockがcompletionBlockをコピーしていないのではないかと考えたので、ブロック内で(ブロック)変数を明示的に宣言し、それを割り当てて保持しようとしました(おそらく少しばかげています,しかし、私は ARC の下で実行しているため、手動で保持呼び出しを行うことはできません)。

とにかく、UIView に渡されたときに複合ブロックが保持されていることは明らかですが、ARC で実行しているため、複合ブロック内に onCompletion/innerCompletionBlock を保持する方法がわかりません。

前もって感謝します :)

4

2 に答える 2

1

Aha, figured it out. Bit stupid, really.

There are various times where I was calling the method - (void)moveToPosition:... and passing nil to the completionBlock parameter...because I just didn't need to do anything extra at the end of the animation and only wanted the [self unlockInteractionFromPullDownMenuTab]; that was tacked on in the compoundBlock.

Makes sense, right?

...Only if you check for nil before you call the block. As discussed elsewhere on SO, "When you execute a block, it's important to test first if the block is nil". Well, I learned my lesson there.

This code works:

// Compound completion block
void (^compoundBlock) (BOOL completed) = ^(BOOL completed) {
    [self unlockInteractionFromPullDownMenuTab];
    if (completionBlock != nil) {
        completionBlock(completed);
    }
};
于 2012-10-07T03:36:56.193 に答える
0

ブロックはスタック上に作成されます。ヒープにコピーする必要があるcompletionBlockため、実行しようとしたときにまだ有効であることを確認できます。これをメソッドの先頭に置くだけです:

completionBlock = [completionBlock copy];

completionBlockすでにヒープ上にある場合、これは同じヒープ コピーを返すだけであることに注意してください。

于 2012-10-07T03:32:24.247 に答える