drawRect выдает "фатальную ошибку: неожиданно найденный ноль при развертывании необязательного значения" в игровой площадке Xcode

Почему ниже код бросает fatal error: unexpectedly found nil while unwrapping an Optional value когда запустить на детской площадке Xcode? Я не уверен, что не так с кодом ниже. Спасибо за вашу помощь. Я не пытался запустить его за пределами детской площадки.

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

1 ответ

Вы не должны использовать init(layer:) инициализатор для того, чтобы создать свой CAShapeLayers, Из документации (выделено мое):

Этот инициализатор используется для создания теневых копий слоев, например, для метода presentationLayer. Использование этого метода в любой другой ситуации приведет к неопределенному поведению. Например, не используйте этот метод для инициализации нового слоя с содержимым существующего слоя.

Следовательно, поскольку поведение вызова этого инициализатора не определено в этих обстоятельствах, оно возвращает nil в вашем случае - который вы затем принудительно распаковываете при доступе, так как это неявно распакованный необязательный параметр.

Вместо этого вы должны просто создать свои слои с init(), Я бы также порекомендовал вам определить встроенные экземпляры слоя и избавиться от неявно развернутых опций, поскольку они по своей сути небезопасны. Например:

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

Это именно то, что UIView реализация init уже

Другие вопросы по тегам