【问题标题】:adding catextlayers to calayer in a background task在后台任务中将 catextlayers 添加到 calayer
【发布时间】:2015-11-11 11:59:06
【问题描述】:

我有一种情况,我不明白。 我喜欢在后台任务中创建 CATextLayers 并在我的视图中显示它们,因为这需要一些时间。

这在没有后台任务的情况下完美运行。我可以立即在我的视图“worldmapview”中看到文本

@IBOutlet var worldmapview: Worldmapview! // This view is just an empty view.

    override func viewDidLoad(){

         view.addSubview(worldmapview);

    }
func addlayerandrefresh_direct(){
                var calayer=CALayer();
                var newtextlayer:CATextLayer=create_text_layer(0,y1: 0,width:1000,heigth:1000,text:"My Text ....",fontsize:5);

                    self.worldmapview.layer.addSublayer(newtextlayer)
                    //calayer.addSublayer(newtextlayer);
                    calayer.addSublayer(newtextlayer)
                    self.worldmapview.layer.addSublayer(calayer);
                    self.worldmapview.setNeedsDisplay();
  }  

在后台任务中执行此操作时,文本不会出现在我的视图中。有时,并非总是如此,它会在几秒钟后出现(例如 10 秒钟)。

func addlayerandrefresh_background(){
            let qualityOfServiceClass = QOS_CLASS_BACKGROUND
            let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)

           dispatch_async(backgroundQueue, {

                var calayer=CALayer();
                var newtextlayer:CATextLayer=create_text_layer(0,y1: 0,width:1000,heigth:1000,text:"My Text ....",fontsize:5);
                dispatch_async(dispatch_get_main_queue(),{

                    self.worldmapview.layer.addSublayer(newtextlayer)
                    //calayer.addSublayer(newtextlayer);
                    calayer.addSublayer(newtextlayer)
                    self.worldmapview.layer.addSublayer(calayer);
                    self.worldmapview.setNeedsDisplay();
                })

            })
     }
    func create_text_layer(x1:CGFloat,y1:CGFloat,width:CGFloat,heigth:CGFloat,text:String,fontsize:CGFloat)  -> CATextLayer {
        let textLayer = CATextLayer()
        textLayer.frame = CGRectMake(x1, y1, width, heigth);
        textLayer.string = text
        let fontName: CFStringRef = "ArialMT"
        textLayer.font = CTFontCreateWithName(fontName, fontsize, nil)
        textLayer.fontSize=fontsize;
        textLayer.foregroundColor = UIColor.darkGrayColor().CGColor
        textLayer.wrapped = true
        textLayer.alignmentMode = kCAAlignmentLeft
        textLayer.contentsScale = UIScreen.mainScreen().scale
        return textLayer;
    }

有人看到了吗,怎么了? 非常令人困惑的是:在后台使用 CAShapeLayer 也是如此。

【问题讨论】:

  • 请查看我的回答。我认为这个问题不需要赏金。这很简单:)
  • 嗨,法瓦德。这对你来说可能很简单:-),但我仍然不知道该怎么做。你能帮我更多吗?我的代码可以粘贴来重现问题。我很高兴看到让这个工作的更正。因为从理论和阅读文档来看,我仍然不明白。
  • 你说“这在没有后台任务的情况下完美运行”,那你为什么要在后台做呢?我已经在主线程上执行了任务(使用您的代码),并且我在 worldMapView 上添加了 100 个子视图,并且没有延迟。请检查是否有其他原因导致延迟。

标签: ios swift calayer cashapelayer


【解决方案1】:

看起来setNeedDisplay 不会导致子层重绘,我们需要在我们需要的所有层上调用它,在这种情况下它是新添加的层

func addlayerandrefresh_background(){
    let calayer = CALayer()
    calayer.frame = self.worldmapview.bounds

    dispatch_async(backgroundQueue, {
        for var i = 0; i < 100 ; i+=10 {
            let newtextlayer:CATextLayer=self.create_text_layer(0, y1: CGFloat(i) ,width:200,heigth:200,text:"My Text ....",fontsize:5)
            calayer.addSublayer(newtextlayer)
        }
        dispatch_async(dispatch_get_main_queue(),{
            self.worldmapview.layer.addSublayer(calayer)
            for l in calayer.sublayers! {
                l.setNeedsDisplay()
            }
        })

    })
}

【讨论】:

  • 同样的问题。 calayer 是我所有 CATextLayers 的图层。我有很多。说 50。我没有定义 calayer 的 sie。我也没有为我的所有 CAShapelayers 图层。解释。我有2层。一种用于文本,一种用于形状。
  • 嗨圣人。感谢您的帮助!我明天试试这个。
  • 嗨圣人。我试过这个,但它没有用。我在 SWIFT 2.0 中编码,我不得不将“0”更改为 DISPATCH_QUEUE_SERIAL。这是正确的吗 ?您也可以使用我的代码(Backgroundtask 案例)并重现问题。它可以粘贴到视图控制器中。
  • @mcflysoft 欢呼,刚刚玩过你的代码,似乎找到了解决方案,在所有方法之后尝试调用newtextlayer.setNeedsDisplay()
  • @mcflysoft 添加了更好的代码示例,并附有解释
【解决方案2】:

UI 上的所有更改都在主线程上执行。您不能在后台线程上更新用户界面。根据Apple's documentation

涉及视图、核心动画和许多其他 UIKit 类的工作 通常必须发生在应用程序的主线程上。有一些例外 遵守这条规则——例如,基于图像的操作经常发生在 后台线程——但是当有疑问时,假设工作需要发生 在主线程上。

【讨论】:

  • 你能解释一下performSelectorOnMainThread: dispatch_async(dispatch_get_main_queue()...的区别吗
  • @sage444 抱歉,由于 CALayer 是一个核心动画类,您不能在后台线程上对其进行更改。我已经更新了答案:)
  • 我必须道歉,我不明白。我想我正在更新主线程中的 GUI。但是你的coden-p,显然已经消失了,这很有趣。我试过了,但 AppDelegate 类出现错误。 “libc++abi.dylib:以 NSException 类型的未捕获异常终止”。答案中的代码在哪里?
  • 我意识到我发布的代码不起作用。因此我删除了它。简单的答案是您不能在主线程上更新 Core Animation 和 UIKit 类。如果你想要代码 sn-p 我可以再发一次。
  • 我很高兴看到代码 sn-p。您可以简单地拿我的代码进行测试。您将拥有一切重现背景任务案例的问题。
猜你喜欢
  • 2016-02-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-16
  • 2011-01-13
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
相关资源
最近更新 更多