👻

iOS 18のiPadでタブがえらいことになってたので戻す

2024/10/14に公開

久々に自作iOSアプリをメンテしてiOS18でテストしてたらタブがえらい変わっててびっくりでした。

https://developer.apple.com/jp/videos/play/wwdc2024/102/?time=2858

https://developer.apple.com/jp/videos/play/wwdc2024/10147/

今までボトムタブバーと呼ばれるようなスタイルだったものがiPadだけ、上部に移動、さらにサブ的な項目を合わせて表示するサイドバーにも変形?するという進化をしていました。

古い実装だとクラッシュ

ただ問題なのは私のswiftの実装のままだとアプリ起動と同時にクラッシュしまい、アプリ自体が利用できなくなっていました。
(なお、SwiftUIへの移行もサボっており、まだstofyboard+swiftという構成)

エラーログは以下の通り。

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors <NSLayoutXAxisAnchor:0x6000017a33c0 "GADBannerView:0x106a6f970.centerX"> and <NSLayoutXAxisAnchor:0x6000017a3440 "UILayoutGuide:0x600003b55ce0'UIViewSafeAreaLayoutGuide'.centerX"> because they have no common ancestor.  Does the constraint or its anchors reference items in different view hierarchies?  That's illegal.'
*** First throw call stack:

多分、ボトムタブバー前提でレイアウトのアンカーをつけていたのでそれが使えなくなったのだと思われます。

対策

https://forums.developer.apple.com/forums/thread/763429
フォーラムに書いてある内容をもとにUITabBarControllerを実装しているクラスのviewDidLoadhorizontalSizeClass = .compactなる設定をしたらiOS17までと同様に戻りました。

class MyTabBarController: UITabBarController {
    override func viewDidLoad() {
        super.viewDidLoad()

        if #available(iOS 18, *){
            if (UIDevice.current.userInterfaceIdiom == .pad) {
                self.traitOverrides.horizontalSizeClass = .compact
            }
        }
// 以下略

どうやら.compactを指定することでiPhoneと同様のレイアウト=ボトムタブバーが適用される、という方法らしい。

...どっかのバージョンで使えなくならないといいけど。

どなたかの参考になれば幸いです。

参考

https://qiita.com/gaussbeam/items/6ec3026a2d0270e42e8e

https://developer.apple.com/jp/videos/play/wwdc2024/102/?time=2858

https://developer.apple.com/jp/videos/play/wwdc2024/10147/

https://note.com/taatn0te/n/nc87bcd599f30

Discussion