在OS X上使用Swift:如何访问当前的CGContext以便在-[NSView drawRect:]中进行绘制

16

设置:

Xcode 6.1
OS X 10.9.5
Swift Mac 基于文档的应用程序目标

问题:

我正在使用Swift创建Cocoa Mac应用程序(而非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
我做错了什么?如何在Swift中获取当前的CGContext以进行绘制?

注意:

我肯定想使用CoreGraphics API。除非在Swift中完全不可能使用CoreGraphics API,请不要回复建议改用AppKit绘图API(即使它们更容易)。我想知道如何在OS X上使用Swift从CoreGraphics进行绘制。


1
楼主在这里。发布问题后我立即意识到-[NSGraphicsContext CGContext]是一个10.10的API。正如我所说,我正在10.9上开发(尽管我的目标使用10.10基础SDK)。所以,这就是问题所在。这个问题很蠢,基本上是我写的Swift代码的第一行,所以我还在摸索中,而且我只是假设我在语法上做错了什么。 - Todd Ditchendorf
3个回答

27

示例

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

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

这非常优雅!但是,它只在Swift 2中有效吗? - Owen Godfrey
在Swift 3+中使用let ctx = NSGraphicsContext.current?.cgContext - Rick

10

不幸的是,CGContext仅适用于10.10+。还有graphicsPort,但其类型为UnsafeMutablePointer<Void>(并且可能需要进行一些处理才能恢复可行的CGContext),在10.10中被弃用。

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


1
明白了,谢谢。看来我确实需要立即转移到10.10上进行开发,以便让自己更容易些。我现在就去做。 - Todd Ditchendorf

2
"Eporediese的回答可以更新为:
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
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接