简体   繁体   English

如何同时执行两个UI更新?

[英]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. 从我通过阅读Apple的文档可以看出,UI更新只能在主线程上运行。

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 scrolling 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. 当您调用updateInBackground方法时,它将创建一个新的后台线程,该线程创建并绘制到上下文中,然后使用该上下文创建一个图像。 If you put this in a custom subclass of UIImageView , then the image will be drawn to the screen automatically. 如果将其放在UIImageView的自定义子类中,则图像将自动绘制到屏幕上。

- (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. 在后台线程中绘图时,不能使用UIKit对象和方法。 All drawing must be done using Quartz functions . 所有绘图必须使用Quartz函数完成。 If you need to use UIKit, the background thread could call a method on the main thread to do that section of the drawing: 如果你需要使用UIKit,后台线程可以调用主线程上的方法来完成绘图的那一部分:

[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. 重要的是要记住,如果你想要平滑的60FPS滚动,你的渲染(以及主线程上的任何其他cpu)每个循环必须少于16 MS,否则你将开始丢帧。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM