如何避免 UIGraphicsGetCurrentContext() 在 Swift 中返回 "nil"?

How do you avoid UIGraphicsGetCurrentContext() returning "nil" in Swift?

我正在尝试学习如何通过 (NSAttributedString background color and rounded corners)...

获得圆形背景突出显示

所以我正在关注 Apple's Core Text Programming Guide 并基本上尝试在 Swift.

中重新创建所有 objective-C 代码

我 运行 遇到 UIGraphicsGetCurrentContext() returning nil

的错误

这是我的 ViewController,在上一个视图中点击按钮时会被推送:

import UIKit
import CoreGraphics

public class HighlightPractiveViewController: UIViewController {

  override public func viewDidLoad() {
    drawRect()
  }

  func drawRect() {

    let context: CGContext = UIGraphicsGetCurrentContext()!
    context.translateBy(x: 0, y: view.bounds.size.height)
    context.scaleBy(x: 1.0, y: -1.0)
    context.textMatrix = CGAffineTransform.identity

    let path = CGMutablePath()

    let bounds = CGRect(x: 10.0, y: 10.0, width: 200.0, height: 200.0)
    path.addRect(bounds)


    let textString = NSString(string: "Hello, World!") // CF & NS are toll-free bridged.

    let attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0)

    CFAttributedStringReplaceString(attrString, CFRangeMake(0, 0), textString)

    let rgbColorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()
    let components: [CGFloat] = [1.0, 0.0, 0.0, 0.8]
    let red: CGColor = CGColor(colorSpace: rgbColorSpace, components: components)!

    CFAttributedStringSetAttribute(attrString, CFRangeMake(0, 12), kCTForegroundColorAttributeName, red)

    let framesetter = CTFramesetterCreateWithAttributedString(attrString!)
    let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)

    CTFrameDraw(frame, context)
  }
}

如何以及在何处正确调用 UIGraphicsGetCurrentContext() 以便它不会 return nil?

您不必在 UIViewController 中实现方法 drawRect()。您必须在自定义 UIView 中执行此操作。

class MyView: UIView {

   override func draw(_ rect: CGRect) {
      super.draw(rect)

      // write what you want to implement here
   }
}

然后将您的自定义 MyView 添加到 UIViewControl 的视图层次结构中。

class HighlightPractiveViewController: UIViewController {

   func viewDidLoad() {
      super.viewDidLoad() // always call super's methods

      let myView = MyView()
      view.addSubview(myView)
   }  
}