【问题标题】:@IBDesignables - "the agent crashed" but app still works (most of the time)@IBDesignables - “代理崩溃”但应用程序仍然有效(大部分时间)
【发布时间】:2021-03-24 22:00:43
【问题描述】:

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

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

这些是我得到的错误:

“更新自动布局状态失败:代理崩溃”

"无法为 {randomly 渲染和更新自动布局状态 选择的 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()
        }
    }
}

谢谢大家的帮助!

【问题讨论】:

  • 我今天也遇到了类似的问题,我尝试debug这个类,发现崩溃可能是由于属性没有初始化,所以你可能需要调试看看是哪个语句它崩溃了。
  • 您的意思是设置断点并逐步执行?我试过了,不幸的是,它没有崩溃。我尝试了多次
  • 不,转到identify inspector,您会在顶部看到Designable 标签,右侧有一个小debug 按钮。点击debug按钮,可以看到是哪条语句让你崩溃了
  • 我没有在身份检查器中找到它,但我使用了“编辑器->调试选定的视图”。我跳过它,它确实崩溃了。我现在来看看这个。也许这就是导致我的问题的原因。谢谢,到目前为止!

标签: ios swift xcode


【解决方案1】:

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

~/Library/Logs/DiagnosticReports

命名为 IBDesignablesAgentCocoaTouch_*.crash

只需进入 Finder(转到->转到文件夹),复制路径并替换为您的用户名。

可能你那里有太多的崩溃日志,你可以将它们全部删除,清理你的项目,重新构建并检查文件夹。

【讨论】:

  • 谢谢,但我已经找到了 :)。在我的问题中,我引用了崩溃日志的错误。还是你的意思是别的?
  • 通常崩溃日志会指定崩溃发生的确切行号,如下所示:AppDelegate.swift:17。你能在那里看到吗?
  • 不,至少我找不到行号
  • 能否提供任何崩溃日志中的堆栈跟踪信息?
  • 不确定,崩溃日志的哪一部分是 :D 但我确实找到了原因(见上面的答案)
【解决方案2】:

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

【讨论】:

  • 问题是:崩溃的视图(在调试时)没有debug 按钮。这是否意味着它不会导致问题?我检查了 m 故事板中的每个 IBDesignable,我找不到任何调试按钮。真奇怪。但我仍然需要弄清楚我刚刚发现的崩溃
  • 好的,我很确定我找到了问题所在。此行(在 layoutSubviews 方法内)导致问题:superview!.addSubview(maxFillLabel)。我相信,superview 为零,这就是它崩溃的原因。这将适合崩溃日志描述。现在我必须解决这个问题。感谢您提供调试提示。直到现在才知道:)
  • 那么您的designable 状态是什么? crash?调试按钮仅在状态等于 crash 时存在。
  • 不,状态是up to date,即使我尝试调试它时它崩溃了
  • 现在我修复了崩溃,所有错误都消失了。但现在我得到Build failed 和它旁边的Show 按钮。但是当我点击它时没有任何反应。此外,视图只是白色的,没有任何内容。但是当我启动应用程序时,它正在工作
【解决方案3】:

我在创建复选框按钮时遇到问题,定义了 2 个 UIImage,用于选中和未选中。 代码运行良好,但代理因 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

终于加了一个draw func

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

如果这可能对其他人有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-31
    • 2012-03-24
    • 1970-01-01
    • 2015-07-14
    • 2011-12-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-21
    相关资源
    最近更新 更多