1

理想的には、特定の関数が実行されたときに目的のビューが実行するアニメーションを決定できるコードを書きたいと思います (nb、疑似コード)。

- (void)animateView:(UIView *)view withAnimations:(NSArray *)arrayOfAnimationBlocks

上記の (つまり、目的の) 関数は、一連のアニメーションを順番に実行し、前のアニメーションが完全に実行されるまで各アニメーションを実行しません。実行時にアニメーションを追加および削除することもできarrayOfAnimationBlocksます。

このようなことをするために、私は以下を使用しようとしています:

[UIView animateWithDuration:duration animations:animationBlock completion:completionBlock];

関数が呼び出されると、すべてのパラメーター ( durationanimationBlock、 )が渡されます。completionBlock

しかし...

selfanimationBlock内からアクセスできないようですね?私のアニメーションブロックには以下が含まれています:

void (^animationBlock)(void) = ^
{
    NSLog(@"[^animationBlock]");
    [self.viewToAnimate setBounds:CGRectMake(self.viewToAnimate.bounds.origin.x, self.viewToAnimate.bounds.origin.y, self.viewToAnimate.bounds.size.width*2, self.viewToAnimate.bounds.size.height*2)];
};

私の完了ブロックには以下が含まれます:

void (^completionBlock)(void) = ^
{
    NSLog(@"[^completionBlock]");
    [UIView animateWithDuration:duration animations:^{
        [self.viewToAnimate setBounds:CGRectMake(self.viewToAnimate.bounds.origin.x, self.viewToAnimate.bounds.origin.y, self.viewToAnimate.bounds.size.width/2, self.viewToAnimate.bounds.size.height/2)];
    } completion:^(BOOL finished){
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Animation Complete" message:@"The previous animations should be fully completed." delegate:self cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
        alert.alertViewStyle = UIAlertViewStyleDefault;
        [alert show];
    }];
};

そしてもちろん私は持っています:

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == 0) NSLog(@"Cancel pressed.");
    else
    {
        NSLog(@"buttonIndex = %i", buttonIndex);
    }
}

animationBlockとXcode の両方でcompletionBlock、次の赤いエラーが発生します。 (!) Use of undeclared identifier 'self'

4

4 に答える 4

2

ジョシュは彼のコメントで正しい答えを出しました。これについて詳しく説明します。以下は無効です。

void (^completionBlock)(void) = ^
{ ... [self something] ... };

@implementation Whatever

...

@end

@implementation(の定義の上に配置されたものと同じですcompletionBlock)宣言するスコープにcompletionBlockは という名前の変数がないためですselfselfクラスのインスタンス メソッド内にのみ存在し、呼び出された特定のインスタンスを参照します。一般的なケースでは、その値を事前に知ることはできません。

したがって、おそらく必要なものは次のようなものです (非 ARC を想定して、関連する場合は自動リリースを切り取ります):

@implementation Whatever

- (dispatch_block_t)completionBlock
{
     return [[^{ ... [self something] ... } copy] autorelease];
}

@end

これにより、適切な自己を指すブロックが動的に生成され、通常のゲッター規則に従って返されます。実行時に実際に行われるのは、ブロックに入る外側の状態を表す情報のパケットが生成されて保存されることだけです。コード生成などはありませんので、コストについて心配する必要はありません。ただしcopy、ブロックはスタック上に存在しようとするため、ヒープに移動せずに戻るのは安全ではないため、必要です。これはcopy、この場合に達成されることです。

UIView スタイルの完了ブロックの場合、同様に次のようなものが必要です。

- (void (^)(BOOL))blockThatTakesABool
{
    return [[^(BOOL var){... [self something] ... } copy] autorelease];
}
于 2012-09-14T23:27:17.617 に答える
0

みなさん、こんにちは。StackOverflowの投稿で、いくつかのシーケンシャルUIViewアニメーションを実行するための最良の方法に出くわしました。今日は、CPAnimationSequenceを使用したユーザーYangによる回答が含まれています。リンクは以下の通りです。

これは素晴らしく見えます!

于 2012-09-16T01:15:16.280 に答える
0

グローバル変数を宣言してブロックに割り当てたようです。したがって、ブロックはグローバル コンテキストで定義され、メソッドの (隠し) 引数のようなものはself存在selfしないため、メソッド内にのみ存在します。

また、グローバル スコープでブロック構文を使用しても意味がありません。ブロックの代わりに関数を書くこともできます。ブロックが存在するまさにその理由は、C (および C++ と Objective-C は C/C++ に基づいて構築されているため) では、ネストされた方法で関数を宣言/定義することが不可能だからです。

ブロックの目的は次のとおりです。

void foo() { ... }

void bar() 
{ 
  ...
  aFun(foo);
  ... 
}

上記は合法ですが、

void bar() 
{ 
   ...
   afun( void foo() { ... } );
   ...
}

C/C++/Objective-C では、関数を別の関数内で定義したり、式でインライン化したりすることはできません。

多くの言語では、式の中で関数をインラインで定義できます。これは、特に関数型スタイルのプログラミングでは非常に便利です。しかし、C/C++/Objective-C はそうではありません。

ブロックが Apple によって Objective-C 用に発明されたのはそのためです (そして、Apple のブロックに非常によく似たC++ ラムダが、言語の C++11 再定義で C++ に追加されました)。実際、ブロックは、式でインラインで定義できる無名関数です。2 番目の例では、ブロックを使用して問題を解決します。

ブロック (およびC++ ラムダ) は、インライン関数と対応するクロージャーの定義に対する言語ネイティブ サポートを提供します (これらの言語ではクロージャーもネイティブの概念ではないため、多くの制限と癖があります)。

これにより、Greenspun のプログラミングの第 10 規則に準拠することがいくらか容易になります。(/私は、保証された末尾呼び出しの最適化がどれほど有用であるかを誰かが理解するのを待っています)。

于 2012-09-14T21:06:02.033 に答える
0

まだお読みでない場合は、Apple の View Programming Guide を実際に読む必要があります。特にアニメーションのセクション

そのドキュメントからのサンプルコードは次のとおりです。

- (IBAction)showHideView:(id)sender
{
    // Fade out the view right away
    [UIView animateWithDuration:1.0
        delay: 0.0
        options: UIViewAnimationOptionCurveEaseIn
        animations:^{
             thirdView.alpha = 0.0;
        }
        completion:^(BOOL finished){
            // Wait one second and then fade in the view
            [UIView animateWithDuration:1.0
                 delay: 1.0
                 options:UIViewAnimationOptionCurveEaseOut
                 animations:^{
                    thirdView.alpha = 1.0;
                 }
                 completion:nil];
        }];
}

完成ブロックのある部分が見えますか?呼び出し元の関数とインラインでブロックを宣言/作成します。初めて始めるときは、常に Apple のコードを見て、できる限り厳密に従う必要があります。より多くの経験を積むと、分岐して他の方法を試すことができます。

于 2012-09-14T23:20:22.453 に答える