Quantm Quantm - 1 month ago 11
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

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

Comments