2016-05-11 4 views
0

Warum der folgende Code wirft fatal error: unexpectedly found nil while unwrapping an Optional value, wenn in Xcode Spielplatz ausgeführt? Ich bin mir nicht sicher, was mit dem folgenden Code falsch ist. Danke für Ihre Hilfe. Ich habe es nicht versucht, es außerhalb des Spielplatzes zu laufen.DrawRect wirft "fataler Fehler: unerwartet gefunden Null beim Entpacken ein optionaler Wert" in Xcode Spielplatz

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 
+0

Woher kommt 'layer' in' setup() '? – Alexander

+0

P.s. Aus diesem Grund sollten Sie implizit ausgepackte Optionen vermeiden. – Alexander

Antwort

2

Sie sollten nicht die init(layer:) initialiser um Ihre CAShapeLayers zu erstellen verwenden. From the documentation (Hervorhebung von mir):

This initializer is used to create shadow copies of layers, for example, for the presentationLayer method. Using this method in any other situation will produce undefined behavior. For example, do not use this method to initialize a new layer with an existing layer’s content.

Daher ist, wie sich das Verhalten dieses initialiser des Aufrufs unter diesen Umständen nicht definiert ist, ist es nil in Ihrem Fall der Rückkehr - die Sie dann beim Zugriff zwingen auszupacken, da es eine implizit ausgepackt ist wahlweise.

Sie sollten stattdessen nur Ihre Schichten mit init() erstellen. Ich würde auch empfehlen, dass Sie Ihre Layer-Instanzen inline definieren und die implizit unverpackten Optionals wie they're inherently unsafe loswerden. Zum Beispiel:

class CircularProgressView: UIView { 
    let progressBackgroundLayer = CAShapeLayer() 
    let progressLayer = CAShapeLayer() 
    let iconLayer = CAShapeLayer() 

... 

Um die Schichten zu Ihrer Ansicht hinzuzufügen, müssen Sie die addSublayer: Verfahren auf der Ebene der Ansicht verwenden. Zum Beispiel:

func setup() { 
    layer.addSublayer(progressBackgroundLayer) 
    layer.addSublayer(progressLayer) 
    layer.addSublayer(iconLayer) 
} 

Auch drawRect: verwendet wird, den Inhalt Ihrer Ansicht zu ziehen, und daher ist völlig der falsche Ort, um den Rahmen Ihrer Schichten werden definiert, (die nur dann, wenn die Grenzen Änderungen Sicht auftreten sollen). Sie sollten stattdessen dies in layoutSubviews tun.

override func layoutSubviews() { 
    progressBackgroundLayer.frame = bounds 
    progressLayer.frame = bounds 
    iconLayer.frame = bounds 
} 

Und schließlich, dieser Code ist sinnlos:

convenience init() { 
    self.init(frame: CGRectZero) 
} 

Das ist genau das, was die UIView Implementierung von init bereits der Fall ist.