Quantm Quantm - 1 year ago 102
Swift Question

@IBDesignables - "the agent crashed" but app still works (most of the time)

I have a pretty strange problem with a project. XCode gives me red errors all the time and says that my IBDesignables have a problem. But the error message differs every time and it's always another view controller affected. I have no idea how to find the cause of the problem. It seems to happen randomly with all IBDesignables I created.

The app does still work. Although, sometimes it doesn't render some views correctly (I have views with a custom drawn mask). It happens rarely, but it does happen.

These are errors I get:


"Failed to update the auto layout status: The agent crashed"

"Failed to render and update the auto layout status for {randomly
chosen VC name}: The agent crashed"


The latter disappears as soon as I click on it. And sometimes, when I'm inside my storyboard, all of the errors go away. When I open any other file, I get multiple red errors (sometimes like 3, sometimes 6 or more).

I checked the crash logs. Every single one of them says:


fatal error: unexpectedly found nil while unwrapping an Optional value


I'm not sure what this means.

I tried cleaning the project and restarting XCode.
Also, I implemented all of the
init
methods.

This following code is a
class
that (almost) always is part of the errors I get. Also, it's the custom drawn view that sometimes doesn't render correctly:

import UIKit

struct TriangleViewLabelDefault {
static let triangleWidth: CGFloat = 20
static let triangleHeight: CGFloat = 10
}

@IBDesignable
class TriangleView: UIView {
let DEFAULT_TRIANGLE_WIDTH: CGFloat = 30
let DEFAULT_TRIAGNLE_HEIGHT: CGFloat = 20


struct Triangle {
static var width: CGFloat = TriangleViewLabelDefault.triangleWidth
static var height: CGFloat = TriangleViewLabelDefault.triangleHeight
static var midXPosition: CGFloat = 0
}

@IBInspectable var triangleWidth: CGFloat = TriangleViewLabelDefault.triangleWidth {
didSet {
Triangle.width = triangleWidth
}
}

@IBInspectable var triangleHeight: CGFloat = TriangleViewLabelDefault.triangleHeight {
didSet {
Triangle.height = triangleHeight
}
}

@IBInspectable var relativePosition: Bool = true {
didSet {
setNeedsDisplay()
}
}

@IBInspectable var triangleMidXOffset: CGFloat = 0 {
didSet {
setNeedsDisplay()
}
}

@IBInspectable var decoration: Bool = true {
didSet {
setNeedsDisplay()
}
}

@IBInspectable var lines: Int = 20 {
didSet {
setNeedsDisplay()
}
}

override init(frame: CGRect) {
super.init(frame: frame)
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

override func draw(_ rect: CGRect) {
super.draw(rect)
calcTriangleMidXPosition()
addLines()
if decoration {
addDecoration()
}

let maskLayer = CAShapeLayer()
maskLayer.frame = bounds

let maskPath = UIBezierPath()
maskPath.move(to: CGPoint(x: 0, y: Triangle.height))
/* Triangle */
maskPath.addLine(to: CGPoint(x: Triangle.midXPosition - Triangle.width, y: Triangle.height))
maskPath.addLine(to: CGPoint(x: Triangle.midXPosition, y: 0))
maskPath.addLine(to: CGPoint(x: Triangle.midXPosition + Triangle.width, y: Triangle.height))
/* */
maskPath.addLine(to: CGPoint(x: bounds.size.width, y: Triangle.height))
maskPath.addLine(to: CGPoint(x: bounds.size.width, y: bounds.size.height))
maskPath.addLine(to: CGPoint(x: 0, y: bounds.size.height))
maskPath.addLine(to: CGPoint(x: 0, y: Triangle.height))

maskPath.close()

maskLayer.path = maskPath.cgPath
layer.mask = maskLayer
}

/// Evaluates the properties set in storyboard. This methods calculates the x-center of the triangle
private func calcTriangleMidXPosition() {
if relativePosition {
Triangle.midXPosition = bounds.size.width / 2 + triangleMidXOffset * bounds.size.width / 2
} else {
Triangle.midXPosition = bounds.size.width / 2 + triangleMidXOffset
}
}

private func addDecoration() {
if let superview = superview {

let topLine = UIView(frame: CGRect(x: 0, y: frame.minY + Triangle.height - 2, width: bounds.size.width, height: 1))
let bottomLine = UIView(frame: CGRect(x: 0, y: frame.minY + Triangle.height - 4, width: bounds.size.width, height: 1))

topLine.backgroundColor = UIColor.white
bottomLine.backgroundColor = UIColor.white

topLine.alpha = 0.5
bottomLine.alpha = 0.2

superview.insertSubview(topLine, belowSubview: self)
superview.insertSubview(bottomLine, belowSubview: self)
}
}

private func addLines() {

guard lines > 0 else {
return
}

let paddingLeft: Int = 20
let lineLength: Int = 25

let linesLayer = CAShapeLayer()
linesLayer.frame = bounds

let padding: CGFloat = 20

let minY = Triangle.height + padding
let maxY = bounds.height - padding
let yArea = maxY - minY



for x in 0...lines {
let path = UIBezierPath()
path.lineWidth = 3.0

path.move(to: CGPoint(x: CGFloat(paddingLeft), y: minY + CGFloat(x) * yArea / CGFloat(lines)))
path.addLine(to: CGPoint(x: CGFloat(paddingLeft) + CGFloat(lineLength), y: minY + CGFloat(x) * yArea / CGFloat(lines)))

UIColor(red: 200.0/255.0, green: 200.0/255.0, blue: 200.0/255.0, alpha: 1.0).setStroke()
path.stroke()
}
}
}


Thank you guys for any help!

Answer Source

If your code make you crash, you should found a debug button in the identify inspector as screenshot below. After you click the debug button, you can found out which statement make you crash.

enter image description here

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download