drawRect 在 Xcode 游乐场抛出“致命错误:在展开可选值时意外发现 nil”
Posted
技术标签:
【中文标题】drawRect 在 Xcode 游乐场抛出“致命错误:在展开可选值时意外发现 nil”【英文标题】:drawRect throws "fatal error: unexpectedly found nil while unwrapping an Optional value" in Xcode playground 【发布时间】:2016-05-11 16:17:26 【问题描述】:为什么下面的代码在 Xcode 游乐场运行时会抛出 fatal error: unexpectedly found nil while unwrapping an Optional value
?我不确定下面的代码有什么问题。谢谢你的帮助。我还没有尝试在操场外运行它。
import UIKit
import XCPlayground
class CircularProgressView: UIView
var progressBackgroundLayer: CAShapeLayer!
var progressLayer: CAShapeLayer!
var iconLayer: CAShapeLayer!
override init(frame: CGRect)
super.init(frame: frame)
self.setup()
required init?(coder aDecoder: NSCoder)
super.init(coder: aDecoder)
self.setup()
convenience init()
self.init(frame: CGRectZero)
func setup()
progressBackgroundLayer = CAShapeLayer(layer: layer)
progressLayer = CAShapeLayer(layer: layer)
iconLayer = CAShapeLayer(layer: layer)
override func drawRect(rect: CGRect)
progressBackgroundLayer.frame = self.bounds
progressLayer.frame = self.bounds
iconLayer.frame = self.bounds
var progressView = CircularProgressView(frame: CGRectMake(0, 0, 80, 80))
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
XCPlaygroundPage.currentPage.liveView = progressView
【问题讨论】:
layer
在setup()
中来自哪里?
附言。这就是为什么你应该避免隐式展开的选项。
【参考方案1】:
您不应使用 init(layer:)
初始化程序来创建您的 CAShapeLayers
。 From the documentation(强调我的):
此初始化程序用于创建图层的影子副本,例如,用于presentationLayer 方法。 在任何其他情况下使用此方法都会产生未定义的行为。例如,不要使用此方法用现有图层的内容初始化新图层。
因此,由于在这种情况下调用此初始化程序的行为是未定义的,因此在您的情况下它会返回 nil
- 然后您在访问时强制解包,因为它是一个隐式解包的可选项。
您应该只使用init()
创建图层。我还建议您内联定义您的层实例,并摆脱隐式展开的选项,如they're inherently unsafe。例如:
class CircularProgressView: UIView
let progressBackgroundLayer = CAShapeLayer()
let progressLayer = CAShapeLayer()
let iconLayer = CAShapeLayer()
...
为了将图层添加到您的视图中,您需要在视图的图层上使用addSublayer:
方法。例如:
func setup()
layer.addSublayer(progressBackgroundLayer)
layer.addSublayer(progressLayer)
layer.addSublayer(iconLayer)
另外,drawRect:
用于绘制视图的内容,因此定义层的框架是完全错误的地方(这应该只在视图的边界发生变化时发生)。您应该考虑在 layoutSubviews
中执行此操作。
override func layoutSubviews()
progressBackgroundLayer.frame = bounds
progressLayer.frame = bounds
iconLayer.frame = bounds
最后,这段代码毫无意义:
convenience init()
self.init(frame: CGRectZero)
这正是init
的UIView
实现所做的。
【讨论】:
以上是关于drawRect 在 Xcode 游乐场抛出“致命错误:在展开可选值时意外发现 nil”的主要内容,如果未能解决你的问题,请参考以下文章