Thursday, February 16, 2012

CADisplayLink with NSRunLoopCommonModes not executed for every frame when tracking UIScrollView?


I am trying to execute a small piece of code on every single frame in a regular (non-OpenGL) iPhone app. The goal is to have a frame counter so that I can measure (rather than guess) where the slow points in the app are and fix them to create a better user experience.



What I've done so far is register a CADisplayLink for all modes (including tracking):




CADisplayLink *displayLink = [[CADisplayLink displayLinkWithTarget:self selector:@selector(frame)] retain];
[displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];



The code that is executed looks like this (lastDraw is a NSDate* and count an int):




- (void) frame {
NSDate *newDate = [NSDate date];

if([newDate timeIntervalSinceDate:lastDraw] >= 1) {
label.text = [NSString stringWithFormat:@"%d FPS", count];

count = 0;
[lastDraw release];
lastDraw = [newDate retain];
}

count++;
}



The idea here is to get an update every one second as to how many frames were drawn in the past second.



This seems to work ok, but the numbers are definitely off when scrolling in a UIScrollView: If I just scroll like a normal person then the frame rates seem to make sense. However, if I scroll vigorously up and down then the displayed rate drops down to 1 or 2 fps, but clearly there are more frames drawn than just one every second.



When I change the frame method like such:




- (void) frame {
label.text = [NSString stringWithFormat:@"%f", displayLink.timestamp];
}



It becomes obvious that very few events are fired when I scroll.



I have read a lot of articles here and around the web that deal with UIScrollViews and NSRunLoopCommonModes vs NSDefaultRunLoopMode but haven't found someone describing my problem. The closest I found was in this question




Remember that if a CADisplayLink is unable to fire for a screen refresh (due to the main thread being busy doing things like drawing the previous frame) then it may skip it, as it won't have enough time to complete.




I can't seem to find any evidence for that in the official documentation , though, and hope that I am doing something wrong...



If it makes any difference the device in question is running iOS 4.3.3.

1 comment:

  1. What happens if you add your display link to UITrackingRunLoopMode in addition to NSRunLoopCommonModes?

    ReplyDelete