在后台任务中将 cattextlayers 添加到 calayer

adding catextlayers to calayer in a background task

我有一个情况,我不明白。 我喜欢在后台任务中创建 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 进行同样的操作。

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

Work involving views, Core Animation, and many other UIKit classes usually must occur on the app’s main thread. There are some exceptions to this rule—for example, image-based manipulations can often occur on background threads—but when in doubt, assume that work needs to happen on the main thread.

看起来 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()
            }
        })

    })
}