Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIImage not displayed when added to CALayer in a backgroundtask

in my viewcontroller I have:

@IBOutlet var worldmapview: Worldmapview!


var eventLayer:CALayer=CALayer();

and some function:

func create_picture_layer(pathtopic:String) -> CALayer {
    let bm=getImage(pathtopic,fBitmapsizeSelected: 100)!;
    var calayer_for_picture=CALayer();
    calayer_for_picture.frame=CGRectMake(100, 100, 100, 100);
    calayer_for_picture.contents = bm.CGImage;
    return calayer_for_picture;
}

func createCircleShape(x:CGFloat,y:CGFloat, size:CGFloat) -> CAShapeLayer {

    var test2:UIBezierPath=UIBezierPath(ovalInRect: CGRectMake(x - size/2, y - size/2, size, size));

    var shapelayer:CAShapeLayer=CAShapeLayer();
    shapelayer.backgroundColor=UIColor.clearColor().CGColor;
    //shapelayer.frame=CGRectMake(0, 0, 300, 300);
    shapelayer.fillColor=UIColor.darkGrayColor().CGColor;
    shapelayer.path=test2.CGPath;
    shapelayer.opaque=true

    return shapelayer;
}

func getImage(simagename: String, fBitmapsizeSelected:CGFloat) -> UIImage?{

    var sPathToImage:String=AppProperties.sharedInstance.sPicturePath + simagename;
    let checkValidation = NSFileManager.defaultManager()

    if (!checkValidation.fileExistsAtPath(sPathToImage) || simagename.equals("")){
        // Path to unknown image
        let sunknownimagename:String = "na/na.jpa";
        sPathToImage=AppProperties.sharedInstance.sPicturePath + sunknownimagename;
    }

    let bm:UIImage=UIImage(contentsOfFile: sPathToImage)!;
    var bMapScaled:UIImage;
    if(!bm.isEqual(nil)){
        let newSize:CGSize=CGSizeMake(fBitmapsizeSelected, fBitmapsizeSelected);
        bMapScaled = bm.imageByScalingToSize(newSize,contentMode: UIViewContentMode.ScaleAspectFill)!;
        return bMapScaled;
    }else{
        return nil;
    }
}

In my viewDidAppear(animated: Bool) method I try to show the image in worldmapview

the following code works fine without any background tasks. The image is shown immediately.

// works
let thepicturelayer=create_picture_layer("mypicpath")
eventLayer.addSublayer(thepicturelayer);
worldmapview.layer.addSublayer(eventLayer);
eventLayer.setNeedsDisplay();

in a background task and refreshing in the main task it doesn't work for me. Picture is not shown. After a while it appears, but not always.

// doesn't work

        let qualityOfServiceClass = QOS_CLASS_BACKGROUND
        let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)

        dispatch_async(backgroundQueue, {
            // geht auch mit Eventlayer

            let thepicturelayer=self.create_picture_layer() // This Shape doesn't appear.
            let circleshapelayer=self.createCircleShape(200, y: 200, size: 20) // This shape appears immediatelly.

            self.eventLayer.addSublayer(thepicturelayer);
            self.eventLayer.addSublayer(circleshapelayer);


            dispatch_async(dispatch_get_main_queue(),{
                    //assert(self.eventLayer.sublayers?.count > 0,"no layers in eventLayer !") // just added

                    self.worldmapview.layer.addSublayer(self.eventLayer);
                    //assert(self.worldmapview.layer.sublayers!.count > 0,"no layers in worldmapview!" ) // just added
                    let sublayers=self.eventLayer.sublayers;
                    if sublayers != nil {
                        for l in self.eventLayer.sublayers! {
                            l.setNeedsDisplay()
                        }
                    }
                    //self.updateWorldMapGUI();
                    self.worldmapview.layer.addSublayer(self.eventLayer);
                    //thepicturelayer.setNeedsDisplay();
                    //circleshapelayer.setNeedsDisplay();
                    self.eventLayer.setNeedsDisplay();

            })
        })

Update

I updated the code with a new CAShapelayer added the same way, which is displaying immediately. I do not understand the difference. The Picture is not shown, when created in a background task.

UPDATE2

I realized something confusing to me additionally: Following Code without background task works as already described:

    let thepicturelayer=create_picture_layer()
    eventLayer.addSublayer(thepicturelayer);
    worldmapview.layer.addSublayer(eventLayer);
    eventLayer.setNeedsDisplay();
    //thepicturelayer.setNeedsDisplay(); // When adding this, the picture is not shown.

But activating the last line, the picture doesn't appear. Probably it has something to do with it ? It seems like the content of the calayer is gone ?

like image 411
mcfly soft Avatar asked Nov 10 '22 00:11

mcfly soft


1 Answers

As I understand it, you are creating CALayer in the background, and adding that layer to the UI hierarchy in the background as well.

Would it be reasonable to think that all UI modifications are to happen in the main thread? If so, try this:

let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)

dispatch_async(backgroundQueue, {
    let thepicturelayer=self.create_picture_layer()

    dispatch_async(dispatch_get_main_queue(),{
        self.eventLayer.addSublayer(thepicturelayer);
        assert(self.eventLayer.sublayers) // just added

        self.worldmapview.layer.addSublayer(self.eventLayer);
        assert(self.worldmapview.layer.sublayers) // just added

        self.worldmapview.setNeedsDisplay()
    })
})
like image 61
SwiftArchitect Avatar answered Nov 14 '22 22:11

SwiftArchitect