2

I am hacking this Core Animation example: https://github.com/joericioppo/Shape_05

I want to retrigger the animation in response to an NSThread. The NSLogs show up as expected, but the animation itself does not trigger until all sleeps have completed, even though its method has verifiably been called. How can I retrigger this animation every second?

By the way - this is just an example patch I am working on in order to understand the concept. I know that animations can be set to repeat, but this isn't what I want to do, for various reasons. Here's the code, any help would be most welcome, thanks.

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@interface Shape_05ViewController : UIViewController {

    CALayer                     *rootLayer;

    CAShapeLayer            *shapeLayer;

    CGMutablePathRef        pentagonPath;
    CGMutablePathRef        starPath;

    int animationCount;
    CABasicAnimation *animation;

}

-(void)startAnimation;
-(void) viewDidLoad;
-(void) startSequence;
-(void) enactSequence;

@end

#import "Shape_05ViewController.h"

@implementation Shape_05ViewController


- (void)loadView 
{

    UIView *appView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    appView.backgroundColor = [UIColor blackColor];
    self.view = appView;
    [appView release];
    rootLayer   = [CALayer layer];
    rootLayer.frame = self.view.bounds;
    [self.view.layer addSublayer:rootLayer];


    //Pentagon Path

    pentagonPath = CGPathCreateMutable();
    CGPoint center = self.view.center;
    CGPathMoveToPoint(pentagonPath, nil, center.x, center.y - 75.0);

    for(int i = 1; i < 5; ++i) {
        CGFloat x = - 75.0 * sinf(i * 2.0 * M_PI / 5.0);
        CGFloat y =  - 75.0 * cosf(i * 2.0 * M_PI / 5.0);
        CGPathAddLineToPoint(pentagonPath, nil,center.x + x, center.y + y);
    }
    CGPathCloseSubpath(pentagonPath); //This seems to be fixed in 4.0

    //Star Path

    starPath = CGPathCreateMutable();
    center = self.view.center;
    CGPathMoveToPoint(starPath, NULL, center.x, center.y + 75.0);
    for(int i = 1; i < 5; ++i) {
        CGFloat x =  75.0 * sinf(i * 4.0 * M_PI / 5.0);
        CGFloat y =  75.0 * cosf(i * 4.0 * M_PI / 5.0);
        CGPathAddLineToPoint(starPath, NULL, center.x + x, center.y + y);
    };
    CGPathCloseSubpath(starPath);


    //Create Shape

    shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = pentagonPath;
    UIColor *fillColor = [UIColor colorWithWhite:0.9 alpha:1.0];
    shapeLayer.fillColor = fillColor.CGColor; 
    shapeLayer.fillRule = kCAFillRuleNonZero;
    [rootLayer addSublayer:shapeLayer];

}


-(void) viewDidLoad {

    NSLog(@"viewDidLoad");
    animationCount = 0;
    [NSThread detachNewThreadSelector:@selector(startSequence) toTarget:self withObject:nil];

}

-(void) startSequence {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [self enactSequence];
    //[NSThread sleepForTimeInterval:100];

    [pool release];

}
-(void) enactSequence {
    NSLog(@"enactSequence");
    for(int i = 0; i < 4; i++) {
        [NSThread sleepForTimeInterval:1];
        [self performSelector:@selector(startAnimation) withObject:nil];
        [rootLayer setNeedsDisplay];
        NSLog(@"%i", i);
    };

}


-(void)startAnimation
{   
    NSLog(@"startAnimation");

    animation = [CABasicAnimation animationWithKeyPath:@"path"];
    animation.duration = 0.25;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animation.repeatCount = 0;
    animation.autoreverses = NO;
    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = YES;

    if( (animationCount % 2) == 0) {
        animation.fromValue = (id)pentagonPath;
        animation.toValue = (id)starPath;
    } else {
        animation.fromValue = (id)starPath;
        animation.toValue = (id)pentagonPath;
    };


    [shapeLayer addAnimation:animation forKey:@"animatePath"];

    animationCount++;

}


- (void)didReceiveMemoryWarning 
{
    [super didReceiveMemoryWarning];
}


- (void)dealloc
{
    CGPathRelease(starPath);
    CGPathRelease(pentagonPath);
    [super dealloc];
}


@end
Matthias D
  • 1,581
  • 2
  • 13
  • 17

1 Answers1

0

OK after another Google trawl: http://forums.macrumors.com/showthread.php?t=749518&highlight=cabasicanimation

I found out about this thing called NSTimer! Another search of this site revealed some good info: How do I use NSTimer?

And about running NSTimer in its own thread: Keep an NSThread containing an NSTimer around indefinitely? (iPhone)

So now I can offer this updated code example, which I hope may be useful to someone one day. By the way, I didn't try it yet, but apparently the following can be used to stop the timer:

[myTimer invalidate];
myTimer = nil;

Thanks to all here at this site, not only the most beautifully designed corner of the web but also a total lifesaver!

    #import <UIKit/UIKit.h>
    #import <QuartzCore/QuartzCore.h>

    @interface Shape_05ViewController : UIViewController {

        CALayer                     *rootLayer;

        CAShapeLayer            *shapeLayer;

        CGMutablePathRef        pentagonPath;
        CGMutablePathRef        starPath;

        int animationCount;
        CABasicAnimation *animation;
        NSTimer *repeatingTimer;

    }

@property (assign, readwrite) NSTimer *repeatingTimer;

    -(void) startAnimation: (NSTimer*)theTimer;
    -(void) viewDidLoad;
    -(void) startSequence;

    @end

    #import "Shape_05ViewController.h"

    @implementation Shape_05ViewController

    @synthesize repeatingTimer;


    - (void)loadView 
    {

        UIView *appView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        appView.backgroundColor = [UIColor blackColor];
        self.view = appView;
        [appView release];
        rootLayer   = [CALayer layer];
        rootLayer.frame = self.view.bounds;
        [self.view.layer addSublayer:rootLayer];


        //Pentagon Path

        pentagonPath = CGPathCreateMutable();
        CGPoint center = self.view.center;
        CGPathMoveToPoint(pentagonPath, nil, center.x, center.y - 75.0);

        for(int i = 1; i < 5; ++i) {
            CGFloat x = - 75.0 * sinf(i * 2.0 * M_PI / 5.0);
            CGFloat y =  - 75.0 * cosf(i * 2.0 * M_PI / 5.0);
            CGPathAddLineToPoint(pentagonPath, nil,center.x + x, center.y + y);
        }
        CGPathCloseSubpath(pentagonPath); //This seems to be fixed in 4.0

        //Star Path

        starPath = CGPathCreateMutable();
        center = self.view.center;
        CGPathMoveToPoint(starPath, NULL, center.x, center.y + 75.0);
        for(int i = 1; i < 5; ++i) {
            CGFloat x =  75.0 * sinf(i * 4.0 * M_PI / 5.0);
            CGFloat y =  75.0 * cosf(i * 4.0 * M_PI / 5.0);
            CGPathAddLineToPoint(starPath, NULL, center.x + x, center.y + y);
        };
        CGPathCloseSubpath(starPath);


        //Create Shape

        shapeLayer = [CAShapeLayer layer];
        shapeLayer.path = pentagonPath;
        UIColor *fillColor = [UIColor colorWithWhite:0.9 alpha:1.0];
        shapeLayer.fillColor = fillColor.CGColor; 
        shapeLayer.fillRule = kCAFillRuleNonZero;
        [rootLayer addSublayer:shapeLayer];

    }


    -(void) viewDidLoad {

        NSLog(@"viewDidLoad");
        animationCount = 0;

        [NSThread detachNewThreadSelector:@selector(startSequence) toTarget:self withObject:nil];

    }

    -(void) startSequence {
        NSLog(@"startSequence");
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                          target:self
                                                        selector:@selector(startAnimation:)
                                                        userInfo:nil 
                                                         repeats:YES];
        [[NSRunLoop currentRunLoop] run];
        self.repeatingTimer = timer;
        [pool release];

    }

-(void)startAnimation: (NSTimer*)theTimer {

        NSLog(@"startAnimation");

        animation = [CABasicAnimation animationWithKeyPath:@"path"];
        animation.duration = 0.25;
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        animation.repeatCount = 0;
        animation.autoreverses = NO;
        animation.fillMode = kCAFillModeForwards;
        animation.removedOnCompletion = NO;

        if( (animationCount % 2) == 0) {
            animation.fromValue = (id)pentagonPath;
            animation.toValue = (id)starPath;
        } else {
            animation.fromValue = (id)starPath;
            animation.toValue = (id)pentagonPath;
        };
        [shapeLayer addAnimation:animation forKey:@"animatePath"];
        animationCount++;

    }


    - (void)didReceiveMemoryWarning 
    {
        [super didReceiveMemoryWarning];
    }


    - (void)dealloc
    {
        CGPathRelease(starPath);
        CGPathRelease(pentagonPath);
        [super dealloc];
    }

    @end
Community
  • 1
  • 1
Matthias D
  • 1,581
  • 2
  • 13
  • 17