Search code examples
multithreadingswiftmacosscreensaver

OSX: Creating a thread in a screensaver


I'm creating a simple screensaver for OSX and want to create a thread for some background calculations.

I found this function here in SO that will create a thread after X seconds:

func backgroundThread(delay: Double = 0.0, background: (() -> Void)? = nil, completion: (() -> Void)? = nil) {
    dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.rawValue), 0)) {
        if(background != nil){ background!(); }

        let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
        dispatch_after(popTime, dispatch_get_main_queue()) {
            if(completion != nil){ completion!(); }
        }
    }
}

But it doesn't seem to work when I add it to init :

override init?(frame: NSRect, isPreview: Bool) {
    super.init(frame: frame, isPreview: isPreview);
    let fontSize: CGFloat = 20;
    let frameHeight: CGFloat = self.frame.size.height;
    let font = NSFont(name: "Times New Roman", size: fontSize);
    let paragraph = NSMutableParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle;
    paragraph.alignment = NSTextAlignment.Center;
    let textColor = NSColor(calibratedRed: 255.0, green: 255.0, blue: 255.0, alpha: 1.0);

    self.backgroundThread(3.0, background: {

        let w:String = "test";
        let textRect: NSRect = NSMakeRect(1, (frameHeight-CGFloat(fontSize*CGFloat(1))-30), 80, 30);
        if let actualFont = font {
            let textFontAttributes = [
                NSFontAttributeName: actualFont,
                NSForegroundColorAttributeName: textColor,
                NSParagraphStyleAttributeName: paragraph
            ];

            w.drawInRect(NSOffsetRect(textRect, 0, 1), withAttributes: textFontAttributes);
        }
    });
}

It should display that string after 3 seconds in a different thread but it doesn't. What am I missing?


Solution

  • The GUI thread must be the main thread, not the background one

    So use the completion closure

    self.backgroundThread(3.0, completion: {
    

    Or use only the necessary code

    dispatch_after(3.0, dispatch_get_main_queue()) {
        ...
    }
    

    Or use a framework like Eki