Objective-C块内的静态变量?

Sal*_*rtz 5 cocoa-touch objective-c objective-c-blocks

我正在研究一些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];
Run Code Online (Sandbox Code Playgroud)

"动画的名称"和"某些页码"是占位符以便解释(它们是任意的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];
 }
Run Code Online (Sandbox Code Playgroud)

到目前为止一切都那么好,只有如果我从导航控制器弹出小册子(也就是在小册子上调用dealloc)然后再将其推入,静态布尔仍然设置.

我的想法:

- 我保留了这块? 我不知道..我在将它(带有副本)添加到字典后调用release,并且小册子的dealloc方法调用字典上的release.

- 我在哪里保留静态bool的另一个副本? 当我在方法范围内将块声明为静态时,我的第一个bool被分配.很好地取决于Objective-C的激活记录方案,我没有考虑过.但假设是这样,当在popViewcOntroller上释放对象时,该副本就消失了.当字典被杀死时,应该在将字符串中的副本添加到字典时释放它的另一个副本吗?

我是否保留整个宣传册内容?我没有完全从Apple文档中获取它,但他们说如果我通过引用访问实例变量,我保留自己.我尝试从块内释放自我,一切都运行得很好......?

Pau*_*l.s 1

让块返回一个值,然后决定是否从字典中删除该块。

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

    if (shouldRemove) {
        [pageBlocks removeObjectForKey:key];
    }
// ...
Run Code Online (Sandbox Code Playgroud)

让我们测试一下静态变量

@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];
}
Run Code Online (Sandbox Code Playgroud)

这输出

#=> 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
Run Code Online (Sandbox Code Playgroud)

我们如何解决这个问题呢?一旦像这样执行,我可能会从字典中删除该对象

- (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];
}
Run Code Online (Sandbox Code Playgroud)