Questo articolo è anche disponibile in italiano: iOS Dev: come risolvere 'Failed to render and update autolayout' status causato da @IBDesignable
A picture is worth a thousand word, they say.
This is what Apple might have been thinking when they introduced the properties @IBDesignable and @IBInspectable in XCode 6, during WWDC 2014.
These properties let us see a preview and inspect properties of our custom views and controls just inside the storyboard.
"It just works!"... or does it?
Even today, with XCode 9 and Swift 4, problems arise when we use UIVIew subclass, customized in a different Xib file: XCode can't redraw our custom view, and usually can't redraw the rest of the storyboard either.
But since the app in the simulator is still working as expected, we usually scrap it off as one of the may quirks of XCode's storyboard-based development, and we go on with our life.
Why does this happen, though?
This happens because the process that renders the views in XCode halts, and reminds us of the problem with this kind of messages:
- Failed to render and update auto layout status for X: The agent threw an exception
- Failed to render and update auto layout status for X: The agent crashed
where X is the viewcontroller or view in whose hierarchy our @IBDesignable custom view (or custom control) resides.
What causes the problem then? To keep things simple and concise, let's just say that XCode doesn't render the storyboard previews on its own, but through a different app with a different bundle...
How do you define a custom UIView?
Usually, in Swift 4 with XCode 9, we create two files, e.g. TestView.xib and its file's owner, TestView.swift, defined as such:
import UIKit @IBDesignable class TestView: UIView { @IBOutlet var theView: UIView! // The main UIView in the Xib @IBInspectable var someString: String? override init(frame: CGRect) { super.init(frame: frame) commonInit() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonInit() } private func commonInit() { Bundle.main.loadNibNamed(String(describing: TestView.self), owner: self, options: nil) addSubview(testView) } }
How to solve the error?
That Bunde.main call should now sound familiar...
Since the rendering of the preview goes through a different app... Bundle.main will be referring to that bundle, and so the Xib deserialization will always crash.
To solve the error, just put the following lines in place of that call:
let bundle = Bundle(for: TestView.self) bundle.loadNibNamed(String(describing: TestView.self), owner: self, options: nil)
XCode will start previewing our @IBDesignable as expected.
Did you solve the problem?
Is there something you want to add? Does your development team need a professional and custom support in developing native and hybrid apps for iOS and Android?
Contact us! We will be happy to provide you a free quotation.
(Yes, we speak English and work internationally)