Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift on OS X: How to access the current CGContext for drawing in -[NSView drawRect:]

Setup:

Xcode 6.1
OS X 10.9.5
Swift Mac Document-based Application target

Question:

I am using Swift to make a Cocoa Mac app (NOT iOS!). I have a custom NSView subclass. I'd like to override -drawRect:, and access the current CGContext to do some drawing using the CoreGraphics APIs.

However, I can't seem to access the current CGContext in Swift (something I've done hundreds of times in ObjC). Here's my code:

import Cocoa

class Canvas: NSView {
    override func drawRect(dirtyRect: CGRect) {
        if let ctx: CGContext! = NSGraphicsContext.currentContext()?.CGContext {
            // do drawing
        }
    }
}

When I run, I get an immediate crash on the first line of my drawRect implementation:

-[NSWindowGraphicsContext CGContext]: unrecognized selector sent to instance 0x60800005e840

What am I doing wrong? How do I fetch the current CGContext for drawing in Swift?

NOTE:

I definitely want to use the CoreGraphics API. Unless using the CoreGraphics API in Swift is entirely impossible, please do not respond with suggestions on how to use AppKit drawing APIs instead (I don't care if they are easier). I want to know how to use CoreGraphics from Swift on OS X.

like image 867
Todd Ditchendorf Avatar asked Mar 19 '15 23:03

Todd Ditchendorf


1 Answers

Example

Swift 3+

class CustomView: NSView {

    private var currentContext : CGContext? {
        get {
            if #available(OSX 10.10, *) {
                return NSGraphicsContext.current?.CGContext
            } else if let contextPointer = NSGraphicsContext.currentContext()?.graphicsPort {
                let context: CGContextRef = Unmanaged.fromOpaque(COpaquePointer(contextPointer)).takeUnretainedValue()
                return context
            }

            return nil
        }
    }

    private func saveGState(drawStuff: (ctx:CGContextRef) -> ()) -> () {
        if let context = self.currentContext {
            CGContextSaveGState (context)
            drawStuff(ctx: context)
            CGContextRestoreGState (context)
        }
    }

    override func drawRect(dirtyRect: NSRect) {
        super.drawRect(dirtyRect)

        saveGState { ctx in
            // Drawing code here.
        }
    }
}

Swift 2

class CustomView: NSView {

    private var currentContext : CGContext? {
        get {
            if #available(OSX 10.10, *) {
                return NSGraphicsContext.currentContext()?.CGContext
            } else if let contextPointer = NSGraphicsContext.currentContext()?.graphicsPort {
                let context: CGContextRef = Unmanaged.fromOpaque(COpaquePointer(contextPointer)).takeUnretainedValue()
                return context
            }

            return nil
        }
    }

    private func saveGState(drawStuff: (ctx:CGContextRef) -> ()) -> () {
        if let context = self.currentContext {
            CGContextSaveGState (context)
            drawStuff(ctx: context)
            CGContextRestoreGState (context)
        }
    }

    override func drawRect(dirtyRect: NSRect) {
        super.drawRect(dirtyRect)

        saveGState { ctx in
            // Drawing code here.
        }
    }
}
like image 76
Eporediese Avatar answered Sep 25 '22 09:09

Eporediese