単純なレイアウトで UIAlertController
の actionSheet
を使ったときになぜか Auto Layout がうまく言ってないようだったのでメモ。
現象
ここでは例としてボタンをタップしたらアクションシートを表示するだけのコードを用意しました。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func showActionSheet(_ sender: Any) {
let alert = UIAlertController(title: "title", message: "message", preferredStyle: .actionSheet)
let defaultAction = UIAlertAction(title: "item", style: .default, handler: nil)
alert.addAction(defaultAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addAction(cancelAction)
present(alert, animated: true, completion: nil)
}
}
これを Xcode 11.4, iOS 13.3 の端末で実行すると、こんなログがだらだらと流れてきました。
2020-05-10 22:14:35.759481+0900 UIKitCustomCollection[53013:10180992] [LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<NSLayoutConstraint:0x2806e9720 UIView:0x103e0d040.width == - 16 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x2806e9720 UIView:0x103e0d040.width == - 16 (active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
(lldb)
幅が16のコンテンツに覚えはないし <NSLayoutConstraint:0x2806e9720 UIView:0x103e0d040.width == - 16 (active)>
と言われているので、ViewHierarchyで 0x103e0d040
を絞り込んでみたところ、UIAlertController の中の要素っぽいです。
原因
いろいろググってみたところ、iOS 12.2 から(少なくとも iOS 13.4 まで)存在している、OS 側のバグのようです。
Radarはこちら。
Action sheet causes LayoutConstraints warning
対処法
うまくいった対処法は以下の Stack Overflow の方法です。
https://stackoverflow.com/questions/55653187/swift-default-alertviewcontroller-breaking-constraints
extension UIAlertController {
override open func viewDidLoad() {
super.viewDidLoad()
pruneNegativeWidthConstraints()
}
private func pruneNegativeWidthConstraints() {
for subView in self.view.subviews {
for constraint in subView.constraints where constraint.debugDescription.contains("width == - 16") {
subView.removeConstraint(constraint)
}
}
}
}
本当に今回のバグで発生した width == - 16
だけを remove してるのか少し不安なところですが、おそらくこれ以外の原因では width == - 16
警告は発生しないのでは…。
おまけ
animeted
を false
にすると解決するという情報もありましたが、私には効果がありませんでした。