如何在Objective-C块中使用reference self作为动画块?

时间:2012-09-14 18:57:11

标签: objective-c animation block

理想情况下,我想编写一些代码,允许我确定在执行某个功能时所需视图执行的动画,例如, (n.b.,伪代码):

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

上述(即,期望的)函数将按顺序经历一系列动画,并且在完全执行前一动画之前不会执行每个动画。我还可以在运行时向arrayOfAnimationBlocks添加和删除动画。

要做这样的事情,我试图使用以下内容:

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

并在调用函数时传递所有参数(durationanimationBlockcompletionBlock)。

然而 ...

好像你无法从animationBlock中访问self?我的动画块包含:

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);
    }
}

animationBlockcompletionBlock中,Xcode都会出现以下红色错误: (!) Use of undeclared identifier 'self'

4 个答案:

答案 0 :(得分:2)

乔希在他的评论中给出了正确答案,我将详细说明。以下内容无效:

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

@implementation Whatever

...

@end

(与@implementation定义之上的completionBlock相同,因为在您声明completionBlock的范围内,没有名为self的变量。 self仅存在于类的实例方法中,并且是指已调用的特定实例 - 在一般情况下,其值不可提前知道。

所以你可能想要的(假设非ARC;如果相关则删除自动释放)是这样的:

@implementation Whatever

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

@end

这将动态生成指向适当self的块,并按照正常的getter规则将其返回。在运行时实际发生的所有事情都是生成并存储表示进入块的外部状态的信息包。没有代码生成或类似的东西,所以不要担心成本。但是你确实需要copy因为块试图存在于堆栈中,因此在不移动到堆的情况下返回是不安全的,这是copy在这种情况下实现的。

对于UIView风格的完成模块,您同样需要类似:

- (void (^)(BOOL))blockThatTakesABool
{
    return [[^(BOOL var){... [self something] ... } copy] autorelease];
}

答案 1 :(得分: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发明块的原因(以及 C ++ lambdas ,非常类似于Apple的块,在C ++ 11中重新定义了该语言时添加到C ++中)。实际上,块是匿名函数,您可以在表达式中内联定义。在第二个示例中,您将使用块来解决问题。

Blocks(和 C ++ lambdas )为内联函数的定义和相应的闭包提供了语言本机支持(由于闭包在这些语言中也不是本机概念,因此存在很多限制和怪癖)。

他们让你更容易遵守格林斯彭的第十条编程规则。 (/我等着有人意识到保证尾调用优化也会有用)。

答案 2 :(得分:0)

如果你还没有,你应该阅读Apple的View Programming Guide。特别是section on Animations

以下是该文档中的示例代码:

- (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的代码,并尽可能地密切关注它们。当您获得更多经验时,您可以分支并尝试其他方式来实现它。

答案 3 :(得分:0)

大家好:今天我遇到了StackOverflow帖子Best Way to Perform Several Sequential UIView Animations?,其中包括用户杨使用CPAnimationSequence的答案!链接如下。

看起来很棒!