I have a custom view (inherited from UIView
) in my app. The custom view overrides
- (void) drawRect:(CGRect) rect
The problem is: the drawRect:
executes many times longer on iPad 3 than on iPad 2 (about 0.1 second on iPad 3 and 0.003 second on iPad 2). It's about 30 times slower.
Basically, I am using some pre-created layers and draw them in the drawRect:
. The last call
CGContextDrawLayerAtPoint(context, CGPointZero, m_currentLayer);
takes most of the time (about 95% of total time in drawRect:
)
What might be slowing things so much and how should I fix the cause?
UPDATE:
There are no threads directly involved. I do call setNeedsDisplay:
in one thread and drawRect:
gets called from another but that's it. The same goes for locks (there are no locks used).
The view gets redrawn in response to touches (it's a coloring book app). On iPad 2 I get reasonable delay between a touch and an update of the screen. I want to achieve the same on iPad 3.
So, the iPad 3 is definitely slower in a lot of areas. I have a theory about this. Marco Arment noted that the method renderInContext
is ridiculously slow on the new iPad. I also found this to be the case when trying to create a magnifying glass for a custom text view. In the end I had to forego renderInContext
for custom Core Graphics drawing.
I've also been having problem hitting the dreaded wait_fences
errors on my core graphics drawing here: Only on new iPad 3: wait_fences: failed to receive reply: 10004003.
This is what I've figured out so far. The iPad 3 obviously has 4 times the pixels to drive. This can cause problems in two place:
wait_fences
error, which I believe is simply a call that tells the device to wait a little longer to actually perform the rotation, thus the delay. To avoid memcpy I recommend several things:
I would like to point out that my theory is conjecture. Apple doesn't really explain what exactly they do. My theory is just based on what they have said and how the iPad responds as well as my own experimentation.
UPDATE
So Apple has now released the 2012 WWDC Developer videos. They have two videos that may help you (requires developer account):
One thing they talk about I think may help you is using the method: setNeedsDisplayInRect:(CGRect)rect
. Using this method instead of the normal setNeedsDisplay
and making sure that your drawRect
method only draws the rect given to it can greatly help performance. Personally, I use the function: CGContextClipToRect(context, rect);
to clip my drawing only to the rect provided.
As an example, I have a separate class I use to draw text directly to my views using Core Text. My UIView subclass keeps a reference to this object and uses it to draw it's text rather than use a UILabel. I used to refresh the entire view (setNeedsDisplay
) when the text change. Now I have my CoreText object calculate the changed CGRect and use setNeedsDisplayInRect
to only change the portion of the view that contains the text. This really helped my performance when scrolling.