@IBDesignable崩溃代理

76

当我编写自己的UIButton扩展类并将其设置为@IBDesignable时,在Interface Builder中会收到两个错误提示:

  • Main.storyboard: error: IB Designables:无法更新自动布局状态:代理程序崩溃,因为fd已关闭
  • Main.storyboard: error: IB Designables: 无法呈现RandjeUIButton实例:代理程序已崩溃

这是我的代码:

import UIKit

@IBDesignable
class RandjeUIButton: UIButton {
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        self.backgroundColor = UIColor.blackColor()
    }
}

我正在虚拟机上的 OS X 10.11 beta 2 中使用 Xcode 7 beta 2 进行工作。


11
您需要重写 init(frame: CGRect) 方法。 - Eric Qian
3
我已经完成了,有关代理的错误现在已经被解除了。但是当我在 Identity inspector 中选择标签时,接口构建器仍然显示“构建失败”。 - jbehrens94
1
@EricQian 我也重写了 override init(frame: CGRect) 和 required init?(coder aDecoder: NSCoder) 方法,但仍然出现相同的错误。 - Raj Aggrawal
10个回答

127

Xcode的Interface Builder要求你对于使用@IBDesignable注解的类,需要同时实现或同时不实现两个初始化方法才能在IB中正常渲染。

如果你实现了required init(coder aDecoder: NSCoder)方法,也需要同时重写init(frame: CGRect)方法,否则Xcode会抛出错误并崩溃。

为了解决这个问题,可以将以下代码添加到你的类中:

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

15
我不认为这是原因。我有两种方法,我在7.2上使用。它仍然会崩溃。 - Alok C
1
这是我的问题所在,我删除了 init(frame: CGRect),因为我只是从故事板初始化它。 - Kyle Goslan
3
我也重写了init(frame: CGRect)和required init?(coder aDecoder: NSCoder)方法,但仍然遇到了相同的错误。 - Raj Aggrawal
1
对我来说,这是一个非常困难的调试挑战。我正在对另一个框架(Pod)中存在的类进行子类化。父类有一个init方法没有公共范围(默认为内部)。因此,init方法在我的源代码中不可见。最终,我找到了解决方法,并在我的项目源代码中复制了父类。非常感谢! - K.K
1
这两个初始化可能不够。以UISegmentedControl为例,您还应该实现***override init(items: [Any]?)***。 - Bagusflyer

24

我遇到了同样的问题,并通过以下方式解决:

  1. 问题:

错误:IB Designables:无法更新自动布局状态:代理程序崩溃

  1. 在检查文件中找到调试按钮并单击它。

debug

  1. 然后Xcode将告诉您问题出在哪里。在我的情况下,我在类之前放置了IBDesignable

  2. 然后我进行清除和重建,错误消失了。


嗨@Azure,我也遇到了这个问题。当我按下调试按钮时,Xcode(7.3)没有像您在添加的图像中演示的那样将我移动到导致问题的代码行。这是Xcode的错误吗? - Sauvik Dolui
嗨~你现在解决问题了吗?我也使用Xcode(7.3)。请确保选择导致崩溃的视图并单击调试按钮。 - Azure Yu
2
在点击调试按钮之前,不要忘记创建一个“所有异常”断点,这样调试器将会在崩溃后的几条指令处停止,您可以在堆栈跟踪列表中单击代码,或者直接停在导致崩溃的指令处。 - carlos_ms

12

可能会有许多问题导致这种情况发生。打开控制台,查找崩溃报告IBDesignablesCocoaTouch...

我刚刚解决了一个与valueForKey语义有问题的第三方设计问题。


11
在Xcode 7.3中,以上解决方案都无法解决我的问题,但是这个问题的被接受答案可以解决:Failed to render instance of IB Designables
  1. 清除项目的Xcode派生数据。它们位于~/Library/Developer/Xcode/DerivedData目录下。
  2. 通过按⌘⇧K来清理当前的构建。
  3. 构建您的项目。
  4. 在Storyboard中转到编辑菜单并刷新所有视图;等待构建完成,错误应该就消失了。
我不需要执行第四步即可解决问题(并让我使用PaintCode-drawRect在故事板中绘制UIView),这里只是为了保险起见。
感谢@Mojtaba和@WeZZard。

11

对我来说,让我感到困惑的不是使用#if !TARGET_INTERFACE_BUILDER。基本上,我的一些代码会导致访问Bundle中的路径...

对我而言,问题不在于使用#if !TARGET_INTERFACE_BUILDER这个条件语句。主要是因为我的一些代码导致了试图访问Bundle中的某个路径...

Bundle.main.path(forResource: "Foo", ofType: "plist")

问题是在IB中运行时(而不是在您的应用程序中),Bundle.main不是您的应用程序...

(lldb) po Bundle.main
NSBundle </Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Overlays> (loaded)
所以,简单来说,解决这个问题就是仔细检查你的@IBDesignable UIView代码,并对任何事情(例如我的情况下对CoreLocation的调用)使用#if !TARGET_INTERFACE_BUILDER,因为在设计时运行它们没有意义。

以下是我如何进行调试并找到问题所在:

当您在Storyboard中选择@IBDesignable UIView并使用Editor -> Debug Selected View时,您会看到以下内容:

This is what you see when using the <code>Editor -> Debug Selected View</code> while selecting your <code>@IBDesignable UIView</code> in your storyboard

然后您将在正确的位置崩溃:

The Debug Navigator

在我的情况下,正如您所看到的,initXXXX正在执行一个assert,因为它正在寻找一个文件中的值,而该文件在我的Bundle中,即在Xcode设计时。


如果我们必须使用 #if !TARGET_INTERFACE_BUILDER,那么使用 @IBDesignable 的意义是什么? - Yash Bedi

10

当在任何标记为@IBDesignable的类中使用UIImage时,我发现了一些非常重要的东西。经典的UIImage init会导致代理程序崩溃:

我在标记为@IBDesignable的类中使用UIImage时发现了一个很重要的问题。经典的UIImage init会导致代理崩溃:

let myImage = UIImage(named: String) // crash the agent

解决方法是使用UIImage的init方法:

let myImage = UIImage(named: String, in: Bundle, compatibleWith: UITraitCollection)

工作代码示例:

let appBundle = Bundle(for: type(of: self))
let myImage = UIImage(named: "myImage", in: bundle, compatibleWith: self.traitCollection))

self是使用@IBDesignable关键字的类。

Xcode 9.4,Swift 4.1

遇到了同样的问题,但是是关于UIColor。 - Starwave

9

XCode 10,Swift 4.2

我在这里找到了答案。

解决方案很简单——更改自定义视图类的required init?(coder aDecoder: NSCoder)方法中束缚解决的方式。

    Bundle.main.loadNibNamed(String(describing: TestView.self), owner: self, options: nil)

需要更改为

let bundle = Bundle(for: TestView.self)
bundle.loadNibNamed(String(describing: TestView.self), owner: self, options: nil)

3

我是如何解决这个问题的:

  • 确保输出口被正确初始化
  • @IBInspectable属性应该被正确初始化
  • 在XIB文件中,点击文件的所有者占位符,转到身份验证检查器,并确保它不具有任何默认值

import UIKit

@IBDesignable class TestView: UIView {
    
    @IBOutlet weak var label: UILabel!
    
    
    @IBInspectable var textLabel1: String? {
        get {
            return label.text
        }
        set {
            label.text = newValue
        }
    }

    
    // MARK: Setup
    
    var view1: UIView!
    var nibName: String = "TestView"
    
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        xibSetup()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        xibSetup()
    }
    
    private func xibSetup() {
        view1 = loadViewFromNib()
        
        view1?.frame = self.bounds
        view1?.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
        
        if view1 != nil {
            addSubview(view1!)
            //textLabel1 = "ok"
        }
    }
    
    private func loadViewFromNib() -> UIView? {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: nibName, bundle: bundle)
        for object in nib.instantiateWithOwner(self, options: nil) {
            if let view: UIView = object as? UIView {
                return view
            }
        }
        return nil
    }
    
    
}

用法:

在此输入图片描述


(注:该内容为HTML代码,本人已按照格式要求进行翻译)

2

只需在另一个Xcode设置系统上重新打开代码即可。在我的情况下,这样做是有效的。


这似乎在某些情况下有效。我遇到了同样的问题,尝试了所有可能的方法都无法解决问题,最后我完全关闭了Xcode并打开了另一个没有实现任何@IBDesignable的项目,并打开了代理程序崩溃的项目,错误消息消失了。我没有任何有效的逻辑,但似乎Xcode有一些漏洞:( - dip

1
我花了一整天的时间,最终解决了我的问题。enter image description here 我选择将目标构建为8.0版本,这解决了我所有的问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接