Подтвердить что ты не робот

Swift в OS X: как получить доступ к текущему CGContext для рисования - [NSView drawRect:]

Настройка:

Xcode 6.1
OS X 10.9.5
Swift Mac Цель приложения на основе документов

Вопрос:

Я использую Swift, чтобы создать приложение Cocoa Mac (НЕ iOS!). У меня есть пользовательский подкласс NSView. Я хотел бы переопределить -drawRect: и получить доступ к текущему CGContext, чтобы сделать некоторый чертеж, используя API-интерфейсы CoreGraphics.

Однако я не могу получить доступ к текущему CGContext в Swift (что я делал сотни раз в 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. Если использование API CoreGraphics в Swift полностью невозможно, пожалуйста, не отвечайте на предложения о том, как использовать API-интерфейсы API AppKit (мне все равно, проще ли они). Я хочу знать, как использовать CoreGraphics от Swift на OS X.

4b9b3361

Ответ 1

К сожалению, CGContext доступен только в 10.10+. Theres также graphicsPort, но он имеет тип UnsafeMutablePointer<Void> (и, предположительно, должен быть несколько спорить, чтобы восстановить жизнеспособный CGContext), и его устарело в 10.10.

Если это не кажется жизнеспособным, вы можете создать контекст растрового изображения, используя CGBitmapContextCreate и втянуть в это; то вы можете получить изображение из него и нарисовать это, чтобы увидеть результаты.

Ответ 2

Пример

Свифт 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.
        }
    }
}

Ответ 3

Ответ 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
    }
}