@IBDesignables - “代理崩溃”但应用程序仍然有效(大部分时间)

时间:2016-10-09 09:46:25

标签: ios swift xcode

我对项目有一个非常奇怪的问题。 XCode一直给我红色错误,并说我的IBDesignables有问题。但错误消息每次都不同,并且它总是受到另一个视图控制器的影响。我不知道如何找到问题的原因。它似乎与我创建的所有IBDesignables随机发生。

该应用程序仍然有效。虽然,有时它不能正确渲染一些视图(我有自定义绘制蒙版的视图)。它很少发生,但确实发生了。

这些是我得到的错误:

  

“无法更新自动布局状态:代理程序崩溃”

     

“无法呈现和更新{随机的自动布局状态   选择VC名称}:代理商崩溃了“

一旦点击它就会消失。有时,当我进入故事板时,所有错误都会消失。当我打开任何其他文件时,我会收到多个红色错误(有时像3,有时是6或更多)。

我检查了崩溃日志。他们中的每一个都说:

  

致命错误:在解包可选值时意外发现nil

我不确定这意味着什么。

我尝试清理项目并重新启动XCode。 另外,我实现了所有init方法。

以下代码是class(几乎)总是我得到的错误的一部分。此外,它是自定义绘制的视图,有时无法正确呈现:

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

谢谢你们的帮助!

3 个答案:

答案 0 :(得分:5)

每次发生“代理崩溃”问题时,都会创建崩溃日志。你可以在这里找到所有这些:

/Users/<user>/Library/Logs/DiagnosticReports

命名为IBDesignablesAgentCocoaTouch _ *。崩溃

进入Finder(转到&gt;转到文件夹),复制路径并替换为您的用户名。

你可能会有太多的崩溃日志,你可以删除它们,清理你的项目,再次构建并检查文件夹。

答案 1 :(得分:3)

如果您的代码导致崩溃,您应该在debug中找到identify inspector按钮,如下面的屏幕截图所示。单击调试按钮后,您可以找到导致崩溃的语句。

enter image description here

答案 2 :(得分:0)

我在创建一个复选框按钮时遇到了问题,该按钮定义了2个UIImage,用于选中和未选中。 代码确实运行良好,但是Agent因IBDesignable而崩溃(IBInspectable没问题)

我注意到了几个原因:  不得在类内部创建UIImages 我必须在外部声明一个属性,以保存选定的图像,然后在init(coder)中初始化:

import UIKit
let checkedImage = UIImage(named: "checked")!// as UIImage
let uncheckedImage = UIImage(named: "unchecked")!// as UIImage

@IBDesignable class CheckBox: UIButton {

    @IBInspectable public var image: UIImage?

我必须删除计算属性中的setImage

@IBInspectable public var isChecked: Bool = false { // this caused a crash
   didSet{
      if isChecked == true {
          self.setImage(checkedImage, for: UIControl.State.normal)
      } else {
          self.setImage(uncheckedImage, for: UIControl.State.normal)
      }
   }
}

只保留

@IBInspectable public var isChecked: Bool = false

最后添加了绘画功能

override func draw(_ rect: CGRect) {
    image?.draw(in: rect)
}

如果这可以帮助其他人。