我正在研究一些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。
- 我在某处保留了静态bool的另一个副本吗? 当我在方法范围内将块声明为静态时,我的第一个bool被分配。很好地取决于Objective-C的激活记录方案,我没有考虑过。但假设是这样,当在popViewcOntroller上释放对象时,该副本就消失了。当字典被删除时,应该在将字符串中的副本添加到字典时释放它的另一个副本吗?
我是否保留了整个宣传册对象?我没有完全从Apple文档中获取它,但他们说如果我通过引用访问实例变量,我会保留自己。我尝试从块中释放自我,一切都运行得很好......?
答案 0 :(得分: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];
}
答案 1 :(得分:0)
您的评论
到目前为止一直很好,只有如果我从导航中弹出小册子 控制器(也称为小册子上的dealloc),然后将其推入 再次,静态布尔仍然设置。
似乎暗示你想在推送的视图控制器上有一个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