検証環境:
Xcode 11.3.1
Swift 5.1.3
Storyboard上で IBDesignable を使ったカスタムビューを貼り付けたところ、
error: IB Designables: Failed to render and update auto layout status for UIViewController (nyp-0u-XJD): The agent crashed
というエラーが出ました。
しかしこのメッセージだけではエラーの原因がわからないのでクラッシュログからエラー詳細を調べる方法をメモしておきます。
- まずMac標準のコンソール.app(console.app)を起動します。
検索窓に
IBDesignablesAgent
を入力してフィルタしておきます。対象の Storyboard を開き、メニューの Editor -> Refresh All Views を実行します。
- するとコンソール.appのログに以下のようなクラッシュログが出力されます。
Saved crash report for IBDesignablesAgent-iOS[48380] version 11.3.1 (15706) to IBDesignablesAgent-iOS_2020-03-27-114733_xyk-mbp.crash
クラッシュレポートは
~/Library/Logs/DiagnosticReports/
ディレクトリに保存されるので、今回の場合なら
~/Library/Logs/DiagnosticReports/IBDesignablesAgent-iOS_2020-03-27-114733_xyk-mbp.crash
ファイルを開きます。このエラーログを見たところクラッシュの原因が特定できました。
ログには
Fatal error: Use of unimplemented initializer 'init(frame:)' for class 'MyButton'
と出力されていました。
IBDesignable を使ってるMyButton
クラスのコードを確認してみると、以下の coder が引数の初期化メソッドのみ定義していました。
required init?(coder: NSCoder) { super.init(coder: coder) }
frame が引数の初期化メソッドを追加することでエラーが解消されました。
override init(frame: CGRect) { super.init(frame: frame) } required init?(coder: NSCoder) { super.init(coder: coder) }
ちなみに両方とも書いてない場合はエラーになりません。
おそらく プレビュー時はランタイム時と違って coder ではなく frame 側の初期化メソッドのみ呼ばれるのが関係している気がします。
これにはちょっとハマってしましました。。
参考:
https://blog.kaltoun.cz/debugging-ibdesignable/blog.kaltoun.cz