I canโt speak with the differences of iOS 5.xv 6.x, but when I use CADisplayLink , I never record things like โmove x pixels / pointsโ at each iteration, but I look at the timestamp (more precisely, the delta between my initial timestamp and current timestamp ) and calculate the location depending on how much time has passed, and not on how many frames have passed. Thus, the frame rate does not affect the speed of movement, but rather on smoothness. (And the difference between 30 and 29 is likely to be indistinguishable.)
To quote from the Link to the CADisplayLink class :
After the link to the image is associated with the launch cycle, the selector on the target call is called when the contents of the screens need to be updated. The target can read the timestamp reference values โโto get the display time of the previous frame. For example, an application that displays movies can use a timestamp to calculate the next frame of a video. An application that performs its own animations can use a timestamp to determine where and how displayed objects appear in the upcoming frame. The duration property provides the time between frames. You can use this value in your application to calculate the display frame rate, the approximate display time of the next frame, and adjust the drawing behavior so that the next frame is prepared in time for display.
As a random example, here I am animating a UIBezierPath using the number of seconds elapsed as a parameter.
Or, conversely, if you are dealing with a UIImage frame UIImage , you can calculate the frame number as follows:
@property (nonatomic) CFTimeInterval firstTimestamp; - (void)handleDisplayLink:(CADisplayLink *)displayLink { if (!self.firstTimestamp) self.firstTimestamp = displayLink.timestamp; CFTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp); NSInteger frameNumber = (NSInteger)(elapsed * kFramesPerSecond) % kMaxNumberOfFrames;
Or, even better, to avoid the risk of losing a frame, go ahead and let it run at 60 frames per second and just determine if the frame needs to be updated, and thus you will reduce the risk of frame dropping.
- (void)handleDisplayLink:(CADisplayLink *)displayLink { if (!self.firstTimestamp) self.firstTimestamp = displayLink.timestamp; CFTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp); NSInteger frameNumber = (NSInteger)(elapsed * kFramesPerSecond) % kMaxNumberOfFrames; if (frameNumber != self.lastFrame) {
But often the number of frames is not needed at all. For example, to move a UIView in a circle, you can do something like:
- (void)handleDisplayLink:(CADisplayLink *)displayLink { if (!self.firstTimestamp) self.firstTimestamp = displayLink.timestamp; CFTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp); self.animatedView.center = [self centerAtElapsed:elapsed]; } - (CGPoint)centerAtElapsed:(CFTimeInterval)elapsed { CGFloat radius = self.view.bounds.size.width / 2.0; return CGPointMake(radius + sin(elapsed) * radius, radius + cos(elapsed) * radius); }
By the way, if you use tools to measure the frame rate, this may seem slower than on the device itself. For a matte comment, for the exact frame rate, you should measure it programmatically on a real device using the release build.