5

私はいくつかのCoreAnimationのものに取り組んでいます。いくつかのビューコントローラーを備えたナビゲーションコントローラー。また、ビューコントローラには、「パンフレット」のさまざまな「ページ」用のUISCrollViewがあります。各ページには、ユーザーがそのページにめくったときにトリガーされるアニメーションがある場合があります。

私はこのようなことを試みていました(ワンショットアニメーションの場合)。

void (^animationBlock)() =
  ^{
    static bool alreadyTriggered = NO;
    if(alreadyTriggered)
      return;

    [CATransaction begin];
    [CATransaction setCompletionBlock:
     ^{
       alreadyTriggered = YES;
     }];

    // Do me some animations...

    [CATransaction commit];
  };

  NSMutableDictionary* pageBlocks = [[NSMutableDictionary alloc] init];
  [pageBlocks setObject:[animationBlock copy] forKey:<animation's name>];
  [self.animationBlocks setObject:pageBlocks forKey:<some page number>];

  [pageBlocks release];
  [animationBlock release];

「アニメーションの名前」と「ページ番号」は、説明のためのプレースホルダーです(これらは任意のNSStringリテラルです)。

そして、これらのアニメーションをトリガーするコードは次のとおりです。

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
  int pageNumber = floor(self.scrollView.contentOffset.x / self.scrollView.frame.size.width);
  NSMutableDictionary* pageBLocks = [self.animationBlocks objectForKey:[NSString stringWithFormat:@"page%i",pageNumber]];
  [CATransaction begin];
  for(id key in pageBLocks)
    ((void (^)())[pageBLocks objectForKey:key])();
  [CATransaction commit];
 }

これまでのところ、ナビゲーションコントローラーからパンフレットをポップして(別名、パンフレットのdeallocを呼び出す)、もう一度押し込んだ場合にのみ、静的ブール値が設定されたままになります。

私の考え:

-私はブロックを保持していますか? わかりません。辞書に(コピーを付けて)追加した後、releaseを呼び出しています。また、パンフレットのdeallocメソッドが辞書でreleaseを呼び出しています。

-静的ブールの別のコピーをどこかに保持していますか? 私の最初のブール値は、メソッドのスコープ内でブロックを静的として宣言したときに割り当てられます。これは、私が調べていないObjective-Cのアクティベーションレコードスキームに大きく依存します。しかし、そうだとすると、popViewcOntrollerでオブジェクトを解放すると、そのコピーはなくなります。そして、それを辞書に追加するときにブロック上のコピーを呼び出すことからのそれの別のコピーは、辞書が殺されたときに解放されるべきですか?

パンフレットオブジェクト全体を保持していますか?Appleのドキュメントからは完全には入手できませんでしたが、参照によってインスタンス変数にアクセスした場合、私は自分自身を保持すると言われています。ブロックの中から自分を解放してみましたが、すべてうまくいきました...?

4

2 に答える 2

1

ブロックに値を返すようにしてから、ディクショナリからブロックを削除するかどうかを決定します。

// ...
    BOOL shouldRemove = block();

    if (shouldRemove) {
        [pageBlocks removeObjectForKey:key];
    }
// ...

静的変数をテストしてみましょう

@interface TestClass : NSObject
@end

@implementation TestClass

- (void(^)(void))block;
{
    return [[^{

        static BOOL staticBOOL = NO;

        NSLog(@"%d", staticBOOL);

        staticBOOL = YES;

    } copy] autorelease];
}  

@end

int main(int argc, char *argv[]) {
    NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];

    TestClass *test1 = [[TestClass alloc] init];
    test1.block();
    test1.block();

    TestClass *test2 = [[TestClass alloc] init];
    test2.block();
    test2.block();

    [p release];
}

この出力

#=> 2012-04-23 00:43:38.501 Untitled[8380:707] 0
#=> 2012-04-23 00:43:38.503 Untitled[8380:707] 1
#=> 2012-04-23 00:43:38.503 Untitled[8380:707] 1
#=> 2012-04-23 00:43:38.504 Untitled[8380:707] 1

どうすれば問題を解決できますか?このように実行されたら、おそらく辞書からオブジェクトを削除します

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
{
    NSInteger pageNumber = floor(self.scrollView.contentOffset.x / self.scrollView.frame.size.width);
    NSMutableDictionary *pageBlocks = [self.animationBlocks objectForKey:[NSString stringWithFormat:@"page%i", pageNumber]];

    [CATransaction begin];

    for (id key in [pageBlocks copy]) {
        void (^block)(void) = [pageBlocks objectForKey:key];
        if (block) {
            block();
        }
        [pageBlocks removeObjectForKey:key];
    }

    [CATransaction commit];
}
于 2012-04-22T23:49:19.753 に答える
0

あなたのコメント

これまでのところ、ナビゲーションコントローラーからパンフレットをポップして(別名、パンフレットのdeallocを呼び出す)、もう一度押し込んだ場合にのみ、静的ブール値が設定されたままになります。

プッシュされたViewControllerにメンバー変数が必要であることを意味しているようですBOOL...それが正しければ、を使用してこれを実現できますobjc_setAssociatedObject()

これを実現するために、UIViewControllerにカテゴリを追加する場合があります。

@interface UIViewController (OneShotAnimation)
@property ( nonatomic ) BOOL animationHasBeenPlayed ;
@end

@implementation UIViewController (OneShotAnimation)

-(void)setAnimationHasBeenPlayed:(BOOL)b
{
    objc_setAssociatedObject( self, @"animationHasBeenPlayed", [ NSNumber numberWithBool:b ], OBJC_ASSOCIATION_RETAIN_NONATOMIC ) ;
}

-(BOOL)animationHasBeenPlayed
{
    return [ objc_getAssociatedObject( self, @"animationHasBeenPlayed" ) boolValue ] ;
}

@end
于 2012-04-23T00:40:00.757 に答える