MIDIVis (the frame rate is much better than what you can see in the video)
Matt Rajca
Moving to github
I have just finished moving all of my open source projects over to github. It’s definitely faster and more powerful than Subversion, and I’m glad I have made the switch. All of my future open source projects will also be hosted on my github account, which can be found here.
A quick overview of what’s there so far:
- AnimationChain - a simple demo application that shows how the NSOperation API can be used to chain Core Animation animations together, as described here.
- Mastermind - a simple replica of the classic board game, Mastermind.
- MIDIVis - a Core Animation application that visualizes the notes in MIDI files.
- NXC SDK for Coda - a plugin for Coda that lets NXC programmers easily edit, build, and run NXC programs on the Mac.
- Snake - a simple replica of the classic Snake game for Mac OS X.
- sudoku solver - a simple, single-threaded sudoku solver written in C that uses the backtracking algorithm.
Apple Store madness.
Apple stores don’t have “no smoking” signs. Legally they need them but they “ruin the design of the store”, so for every apple store in the UK they pay £50 a day to keep their windows sign free. Crazy shit.
EDIT: I forgot to include the source, it’s a friend who works in the Apple Store in Norwich, The evidence is the fact that they aren’t actually in the windows.
A chain of Core Animation animations
Chaining CA animations using NSOperation
After reading a blog post on RogueSheep about chaining sequences of Core Animation animations using a custom manager, I decided to implement the same functionality using the NSOperation API.
First off, we need to create a serial NSOperationQueue.
chainQueue = [[NSOperationQueue alloc] init];
[chainQueue setMaxConcurrentOperationCount:1];
We set the maximum number of concurrent operations to 1, so that only one animation will occur at a time. To run multiple animations simultaneously, we can simply create a CAAnimationGroup animation later on.
Next, we need to create a subclass of NSOperation, called AnimationStepOperation, that will take care of invoking the actual animation. The animation itself is defined elsewhere, and we simply take a target and selector that point the operation to it. The operation will stay in the queue for as long as the animation is running.
AnimationStepOperation.h:
@interface AnimationStepOperation : NSOperation {
id _target;
SEL _selector;
BOOL _done;
}
+ (id)stepWithTarget:(id)target action:(SEL)selector;
- (id)initWithTarget:(id)target action:(SEL)selector;
@end
Most of the implementation consists of a basic subclass of NSOperation. Once an operation is ready to run, its start method gets called, in which we invoke the animation. We have to make sure this is done on the main thread, like all other UI updates. Once the animation completes, our operation receives a delegate callback, in which we mark the operation as ‘finished’. At that point, the operation gets removed from the queue and another animation step operation is ready to run.
#import "AnimationStepOperation.h"
@implementation AnimationStepOperation
+ (id)stepWithTarget:(id)target action:(SEL)selector {
return [[[self alloc] initWithTarget:target action:selector] autorelease];
}
- (id)initWithTarget:(id)target action:(SEL)selector {
self = [super init];
if (self) {
_target = target;
_selector = selector;
}
return self;
}
- (BOOL)isConcurrent {
return YES;
}
- (BOOL)isExecuting {
return !_done;
}
- (BOOL)isFinished {
return _done;
}
- (void)start {
[_target performSelectorOnMainThread:_selector withObject:self waitUntilDone:NO];
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_done = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
}
@end
Now that we have our AnimationStepOperation class, we can setup a chain of animations by simply adding each step to the queue.
- (void)startChain {
[chainQueue addOperation:[AnimationStepOperation stepWithTarget:self action:@selector(enter:)]];
[chainQueue addOperation:[AnimationStepOperation stepWithTarget:self action:@selector(changeColor:)]];
[chainQueue addOperation:[AnimationStepOperation stepWithTarget:self action:@selector(rotate:)]];
}
When writing the animation steps, the only thing we need to remember to do, is to register the operation as a delegate of the animation. Otherwise, the operation will stay in the queue even after the animation is complete.
- (void)rotate:(NSOperation *)op {
CABasicAnimation *rot = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rot.toValue = [NSNumber numberWithDouble:-M_PI];
rot.fillMode = kCAFillModeForwards;
rot.removedOnCompletion = NO;
rot.duration = 0.5f;
rot.repeatCount = 2;
rot.delegate = op;
[squareLayer addAnimation:rot forKey:@"rotate"];
}
That’s all there is to it! While there is nothing wrong with Rogue Sheep’s approach towards this problem, the use of the NSOperation API makes the code much cleaner.
Updating Xcode 3.2 to use LLVM/Clang 2.6
A few months ago, a pretty significant update to LLVM/Clang was released. While Apple hasn’t officially updated Xcode to use the new compiler, you can still install it yourself.
- Quit Xcode.
- Download and extract my LLVM/Clang 2.6 archive. This includes all the necessary binaries, man pages, and header files.
- To install LLVM/Clang, simply double-click on the ‘install’ script that’s also found in the archive. The script will conveniently backup the “stable” release of Clang that comes with Xcode, in case anything goes wrong.
New App Store look
On Friday, Apple began rolling out a new look for App Store pages. While the changes are very subtle, there is one nifty, new feature: users can finally add apps to their iTunes Wishlist. I also wouldn’t be surprised if over time, more of the iTunes Store is redesigned to fit the look and feel of iTunes 9.
