web-dev-qa-db-ja.com

Swift OS Xの場合:-[NSView drawRect:]で描画するために現在のCGContextにアクセスする方法

セットアップ:

Xcode 6.1
OS X 10.9.5
Swift Macドキュメントベースのアプリケーションターゲット

質問:

私はSwiftを使用してCocoa Macアプリを作成しています(iOSではありません!)。カスタムのNSViewサブクラスがあります。 -drawRect:をオーバーライドし、現在のCGContextにアクセスして、CoreGraphicsAPIを使用して描画を実行したいと思います。

ただし、Swift(ObjCで何百回も行ったこと)の現在のCGContextにアクセスできないようです)。コードは次のとおりです。

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を取得するにはどうすればよいですか?

注意:

CoreGraphicsAPIを絶対に使いたいです。 SwiftでCoreGraphicsAPIを使用することは完全に不可能でない限り、代わりにAppKit描画APIの使用方法に関する提案を返信しないでください(簡単かどうかは関係ありません)。知りたいです。 OSXでSwiftからCoreGraphicsを使用する方法。

13

残念ながら、CGContextは10.10以降でのみ利用可能です。 graphicsPortもありますが、タイプはUnsafeMutablePointer<Void>(そしておそらく実行可能なCGContextを回復するためにいくらかラングリングする必要があります)、そしてそれは10.10で非推奨になりました。

それが実行可能でないと思われる場合は、CGBitmapContextCreateを使用してビットマップコンテキストを作成し、それに引き込むことができます。次に、そこから画像を取得して描画し、結果を確認できます。

9
Rob Rix

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

Eporediese sの回答は次のように更新できます

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
    }
}
0
freytag