开发者

How to execute two UI updates concurrently?

From what I can tell by reading Apple's documentation, UI updates can only be run on the main thread.

My app does some rendering in the top half of the screen and has a table view in the bottom half. If the user is scrol开发者_开发知识库ling the table while the top half re-draws itself, the table locks up for half a second or so. Is there any way I can improve this situation?


If drawing a view takes a noticeable amount of time, I would suggest drawing it into an image in a background thread when updating, and having the view simply draw the image. This would prevent the main thread from blocking for as long.

The following code shows how to create and draw into a bitmap context from a background thread. When you call the updateInBackground method, it will create a new background thread which creates and draws into a context, then creates an image using that context. If you put this in a custom subclass of UIImageView, then the image will be drawn to the screen automatically.

- (void)updateInBackground {
    [self performSelectorInBackground:@selector(_drawInBackground:) withObject:[NSValue valueWithCGRect:self.bounds]];
}
- (void)_drawInBackground:(NSValue *)boundsValue {
    NSAutoreleasePool *pool = [NSAutoreleasePool new];
    CGRect bounds = [boundsValue CGRectValue];
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    if(!colorSpace) {
        [pool drain];
        return;
    }
    CGContextRef context = CGBitmapContextCreate(NULL,bounds.size.width, bounds.size.height, 8, bounds.size.width * 32, colorSpace, kCGImageAlphaPremultipliedFirst);
    CGColorSpaceRelease(colorSpace);
    if(!context) {
        [pool drain];
        return;
    }
    CGContextConcatCTM(context, CGAffineTransformMake(1,0,0,-1,0,bounds.size.height));

    // do drawing here

    CGImageRef image = CGBitmapContextCreateImage(context);
    [self performSelectorOnMainThread:@selector(setImage:) withObject:[UIImage imageWithCGImage:image] waitUntilDone:YES];
    CGImageRelease(image);
    CGContextRelease(context);
    [pool drain];
}

When drawing in a background thread, you can NOT use UIKit objects and methods. All drawing must be done using Quartz functions. If you need to use UIKit, the background thread could call a method on the main thread to do that section of the drawing:

[self performSelectorOnMainThread:@selector(drawInMainThread:) withObject:[NSValue valueWithPointer:context] waitUntilDone:YES];

- (void)drawInMainThread:(NSValue *)value {
    UIGraphicsPushContext((CGContextRef)[value pointerValue]);
    // do drawing using UIKit
    UIGraphicsPopContext();
}


Sounds like the drawing of the top half is taking a while. Have you run it through instruments?

Its important to remember that if you want a smooth 60FPS scrolling, your rendering(and any other cpu on the main thread) has to take less than 16 MS per loop otherwise you'll start dropping frames.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜