Swift on OS X:如何访问当前CGContext进行绘图-[NSView drawRect:]



设置:

Xcode 6.1
操作系统X 10.9.5
Swift Mac基于文档的应用程序目标

问题:

我正在使用Swift制作CocoaMac应用程序(而非iOS!)。我有一个自定义的NSView子类。我想覆盖-drawRect:,并访问当前的CGContext,以便使用CoreGraphics API进行一些绘图。

然而,我似乎无法在Swift中访问当前的CGContext(我在ObjC中已经做了数百次了)。这是我的代码:

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

当我运行时,我的drawRect实现的第一行立即崩溃:

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

我做错了什么?如何获取当前的CGContext以便在Swift中绘图?

注意:

我肯定想使用CoreGraphics API。除非在Swift中使用CoreGraphics API是完全不可能的,否则请不要回复如何使用AppKit绘图API的建议(我不在乎它们是否更容易)。我想知道如何在OS X上使用Swift的CoreGraphics。

示例

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.
        }
    }
}

不幸的是,CGContext只在10.10+中可用。还有graphicsPort,但它的类型为UnsafeMutablePointer<Void>(可能必须进行一些争论才能恢复一个可行的CGContext),并且在10.10中不推荐使用。

如果这似乎不可行,您可以使用CGBitmapContextCreate创建一个位图上下文并绘制到其中;然后您可以从中检索图像并绘制该图像以查看结果。

Eporedies的答案可以更新为

Swift 4

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

最新更新