【问题标题】:Draw Text in Background thread ios在后台线程中绘制文本 ios
【发布时间】:2012-10-30 07:34:13
【问题描述】:

我正在努力实现的目标

我有一个 UICollectionView,我在其中尝试在后台渲染所有绘图,然后在动画淡入完成后显示。

我已经在图像方面做得很好,但有些绘图只是文本。我需要适当地调整文本的大小,然后在背景中绘制它。

这可能是很多文本,并且在主线程上完成时会产生口吃。

我是如何做到的

我使用CGBitmapContextCreate 处理图像,所以我也尝试使用文本:

-(void)drawTextFromBundle
{
     UIFont * font = [UIFont AvenirLTStdBlackObliqueWithSize:35]; //custom font

     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
         CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
         CGContextRef context = CGBitmapContextCreate(NULL, 250, backgroundHeight - 112, 8, 250 * 4, colorSpaceRef, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
         CGColorSpaceRelease(colorSpaceRef);
         [_text drawInRect:CGRectMake(0, 0, 250, backgroundHeight - 112) withFont:font];
          CGImageRef outputImage = CGBitmapContextCreateImage(context);
          imageRef = outputImage;
         [self performSelectorOnMainThread:@selector(finishDrawingImage) withObject:nil waitUntilDone:YES];
         CGContextRelease(context);
         CGImageRelease(outputImage);
   });
}

详情

这显然不是正确的方法,因为我遇到了很多错误,都涉及 Core Graphics 文本函数,类似于 <Error>: CGContextSetFont: invalid context 0x0

我知道有UIGraphicsGetCurrentContext,但我不确定这是否是线程安全的,因为我听说不是。

请注意,此方法确实是从-drawRect: 方法中调用的。完全相同的上下文参数适用于我的图像。

我可以做些什么来让文本绘制到我想要的任何自定义项,所有这些都在后台安全地完成?如果您能告诉我如何在缩小文本以适合适当大小的同时执行此操作,则可以加分。

再次感谢 SO 团队。

【问题讨论】:

  • 不要尝试从后台线程绘制/操作 UI。图形操作通常必须在主线程上进行。
  • 从 iOS 4 开始,几乎可以肯定 UI 可以在后台绘制
  • 离屏绘图绝对应该在后台线程上完成,但是您无法从您的 drawRect 方法启动该后台线程。 DrawRect 必须绘制已经在等待绘制的东西并快速退出。它的上下文仅在 drawRect 返回之前有效(我害怕思考您的 finishDrawingImage 方法的作用 - 也许您可以发布更多代码?)
  • finishDrawingImage 只是将完成的图像添加到图像视图中,然后调用委托方法表示其已准备好显示。该方法也可以在 drawRect 方法之外使用。

标签: iphone objective-c ios core-graphics grand-central-dispatch


【解决方案1】:

当你改变 UI 时,你需要在主线程(主队列)中。

尝试将以下内容放在主队列中

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, 250, backgroundHeight - 112, 8, 250 * 4, colorSpaceRef, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
    CGColorSpaceRelease(colorSpaceRef);

    dispatch_async(dispatch_get_main_queue(), ^{
        [_text drawInRect:CGRectMake(0, 0, 250, backgroundHeight - 112) withFont:font];
        CGImageRef outputImage = CGBitmapContextCreateImage(context);
        imageRef = outputImage;
        [self performSelectorOnMainThread:@selector(finishDrawingImage) withObject:nil waitUntilDone:YES];
    });

    CGContextRelease(context);
    CGImageRelease(outputImage);
});

【讨论】:

  • 你没有用新渲染的outputImage更新你的用户界面。您刚刚创建了它并向您的self 对象发送了一条消息finishDrawingImage,这只是一种通知回调。您最好将outputImage 作为withObject 参数添加到该方法中。另外,我会避免使用performSelectorOnMainThread,只写[self finishDrawingImage:outputImage];
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-17
相关资源
最近更新 更多